import java.awt.*;
import java.applet.*;
import java.util.*;
import java.io.*;
/*
 *
 * DLobj
 *
 */
abstract class DLobj extends Canvas
{
	final static int WID = 40;
	final static int HT = 40;
	final static int IWID = 20;
	final static int IHT = 20;
	final static Color INHILITE = Color.red;
	final static Color DISCOL = Color.lightGray;
	final static Color ONCOL = Color.yellow;
	final static Color OFFCOL = Color.blue;
	int state = -1;
	int bx = 0;
	int by = 0;
	DLobj dlin[], dlout[];
	int[] dloutin, dlinout;
	DLSim theApplet;
	boolean[] inHilite;

	DLobj() {this.theApplet = null;}
	DLobj(DLSim theApplet){this.theApplet = theApplet;}
	public void paint(Graphics g) {cpaint(0,0,IWID,IHT,g);}
	void cpaint(Graphics g) {cpaint(bx,by,WID,HT,g);}
	abstract protected void cpaint(int bx, int by, int WID, int HT, Graphics g);

	boolean eval()
	{
		int oldstate = state;
		if (dlin[0] != null) state = dlin[0].stateOf(dlinout[0]);
		else state = -1;
		return (oldstate != state);
	}

	void init(int vin, int vout) {
		resize(WID,HT); 
		dlin = new DLobj[vin];
		dlout = new DLobj[vout];
		dlinout = new int[vin];
		dloutin = new int[vout];
		inHilite = new boolean[vin];
	}

	int whichIn(int x, int y) 
	{
		for (int j = 0; j < dlin.length; j++)
			if (y <= by+(j+1)*HT/(dlin.length)) return j;
		return -1;
	}

	int whichOut(int x, int y) {return 0;}

	Point cin(int i) {return new Point(bx, by+(i+1)*HT/(dlin.length+1));}
	Point cout(int k) {return new Point(bx+WID, by+HT/2);}

	int stateOf(int i) {return state;}

	public boolean mouseDown(Event evt, int x, int y)
	{
		DLobj newobj;
		try {
			newobj = (DLobj)(this.getClass().newInstance());
		} catch (Exception e) {return true;}
		newobj.theApplet = this.theApplet;
		newobj.bx = 0;
		newobj.by = 0;
		theApplet.pegboard.objlist.addElement(newobj);
		theApplet.pegboard.repaint();
		return true;
	}

	String serialize()
	{
		String s = this.getClass().getName() + ',' + Integer.toString(state) + ','
					+ Integer.toString(bx) + ',' + Integer.toString(by) + ',';
		for (int i = 0; i < dlin.length; i++)
			s = s + ((dlin[i] == null) ? "-1" : 
				Integer.toString(theApplet.pegboard.objlist.indexOf(dlin[i]))) + ',';
		for (int i = 0; i < dlout.length; i++)
			s = s + ((dlout[i] == null) ? "-1" : 
				Integer.toString(theApplet.pegboard.objlist.indexOf(dlout[i]))) + ',';
		if (this instanceof Labelable) s = s + ((Labelable)this).myLabel();
		return s;
	}
}

class DLand extends DLobj
{
	DLand(DLSim theApplet) {super(theApplet); init(2,1);}
	DLand(){super(); init(2,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/4,HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/2, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+WID/2, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/4, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/3, bx+WID/4, by+HT/3);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+2*HT/3, bx+WID/4, by+2*HT/3);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		if (in0 == -1 && in1 == -1) state = -1;
		else if (in0 == -1 || in1 == -1) state = 0;
		else state = in0 & in1;
		return (oldstate != state);
	}
}

class DLand3 extends DLobj
{
	DLand3(DLSim theApplet) {super(theApplet); init(3,1);}
	DLand3(){super(); init(3,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/4,HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/2, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+WID/2, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/4, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/4, bx+WID/4, by+HT/4);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		if (inHilite[2]) g.setColor(INHILITE);
		g.drawLine(bx, by+3*HT/4, bx+WID/4, by+3*HT/4);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		int in2 = (dlin[2] == null) ? -1 : dlin[2].stateOf(dlinout[2]);		
		if (in0 == -1 && in1 == -1 && in2 == -1) state = -1;
		else if (in0 == -1 || in1 == -1 || in2 == -1) state = 0;
		else state = in0 & in1 & in2;
		return (oldstate != state);
	}
}

class DLor extends DLobj
{
	DLor(DLSim theApplet) {super(theApplet); resize(WID,HT); init(2,1);}
	DLor(){super(); init(2,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/4, HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/2, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+WID/2, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+3*WID/8, by+HT/3);
		g.drawLine(bx+3*WID/8, by+HT/3, bx+3*WID/8, by+2*HT/3);
		g.drawLine(bx+3*WID/8, by+2*HT/3, bx+WID/4, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/3, bx+3*WID/8, by+HT/3);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+2*HT/3, bx+3*WID/8, by+2*HT/3);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		if (in0 == -1) state = in1;
		else if (in1 == -1) state = in0;
		else state = in0 | in1;
		return (oldstate != state);
	}
}

class DLor3 extends DLobj
{
	DLor3(DLSim theApplet) {super(theApplet); resize(WID,HT); init(3,1);}
	DLor3(){super(); init(3,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/4, HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/2, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+WID/2, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+3*WID/8, by+HT/3);
		g.drawLine(bx+3*WID/8, by+HT/3, bx+3*WID/8, by+2*HT/3);
		g.drawLine(bx+3*WID/8, by+2*HT/3, bx+WID/4, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/4, bx+3*WID/8, by+HT/4);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+3*WID/8, by+HT/2);
		g.setColor(hold);
		if (inHilite[2]) g.setColor(INHILITE);
		g.drawLine(bx, by+3*HT/4, bx+3*WID/8, by+3*HT/4);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		int in2 = (dlin[2] == null) ? -1 : dlin[2].stateOf(dlinout[2]);		
		if (in0 == -1) {
			if (in1 == -1) state = in2;
			else if (in2 == -1) state = in1;
			else state = in1 | in2;
		} else if (in1 == -1) {
			if (in2 == -1) state = in0;
			else state = in0 | in2;
		} else if (in2 == -1) state = in1 | in2;
		else state = in0 | in1 | in2;
		return (oldstate != state);
	}
}

class DLnot extends DLobj
{
	DLnot(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,1);}
	DLnot(){super(); init(1,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawLine(bx+WID/4, by+HT/8, bx+WID-WID/3, by+HT/2);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+WID-WID/3, by+HT/2);
		g.drawOval(bx+WID-WID/3, by-HT/11+HT/2, 2*HT/11, 2*HT/11);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/4, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		if (dlin[0] != null && dlin[0].stateOf(dlinout[0]) != -1) 
			state = 1-dlin[0].stateOf(dlinout[0]);
		else state = -1;
		return (oldstate != state);
	}
}

class DLnand extends DLobj
{
	DLnand(DLSim theApplet) {super(theApplet); init(2,1);}
	DLnand(){super(); init(2,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/8-WID/3,HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+2+WID/3, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+2+WID/3, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+WID/4, by+HT-HT/8);
		g.drawOval(bx+WID-WID/3, by-HT/11+HT/2, 2*HT/11, 2*HT/11);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/3, bx+WID/4, by+HT/3);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+2*HT/3, bx+WID/4, by+2*HT/3);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		if (in0 == -1 && in1 == -1) state = -1;
		else if (in0 == -1 || in1 == -1) state = 1;
		else state = 1-(in0 & in1);
		return (oldstate != state);
	}
}

class DLnor extends DLobj
{
	DLnor(DLSim theApplet) {super(theApplet); resize(WID,HT); init(2,1);}
	DLnor(){super(); init(2,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/8-WID/3,HT-HT/4,-90,180);
		g.drawLine(bx+WID/4, by+HT/8, bx+2+WID/3, by+HT/8);
		g.drawLine(bx+WID/4, by+HT-HT/8, bx+2+WID/3, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+3*WID/8, by+HT/3);
		g.drawLine(bx+3*WID/8, by+HT/3, bx+3*WID/8, by+2*HT/3);
		g.drawLine(bx+3*WID/8, by+2*HT/3, bx+HT/4, by+HT-HT/8);
		g.drawOval(bx+WID-WID/3, by-HT/11+HT/2, 2*HT/11, 2*HT/11);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/3, bx+3*WID/8, by+HT/3);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+2*HT/3, bx+3*WID/8, by+2*HT/3);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		if (in0 == -1 && in1 == -1) state = -1;
		else if (in1 == -1) state = 1-in0;
		else if (in0 == -1) state = 1-in1;
		else state = 1-(in0 | in1);
		return (oldstate != state);
	}
}

class DLxor extends DLobj
{
	DLxor(DLSim theApplet) {super(theApplet); resize(WID,HT); init(2,1);}
	DLxor(){super(); init(2,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawArc(bx+WID/8,by+HT/8,WID-WID/4, HT-HT/4,-90,180);
		g.drawLine(bx+3*WID/8, by+HT/8, bx+WID/2, by+HT/8);
		g.drawLine(bx+3*WID/8, by+HT-HT/8, bx+WID/2, by+HT-HT/8);
		g.drawLine(bx+WID/4, by+HT/8, bx+3*WID/8, by+HT/3);
		g.drawLine(bx+3*WID/8, by+HT/8, bx+WID/2, by+HT/3);
		g.drawLine(bx+3*WID/8, by+HT/3, bx+3*WID/8, by+2*HT/3);
		g.drawLine(bx+WID/2, by+HT/3, bx+WID/2, by+2*HT/3);
		g.drawLine(bx+3*WID/8, by+2*HT/3, bx+WID/4, by+HT-HT/8);
		g.drawLine(bx+WID/2, by+2*HT/3, bx+3*WID/8, by+HT-HT/8);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/3, bx+3*WID/8, by+HT/3);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+2*HT/3, bx+3*WID/8, by+2*HT/3);
		g.setColor(hold);
		g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);		
		if (in0 == -1) state = in1;
		else if (in1 == -1) state = in0;
		else state = in0 ^ in1;
		return (oldstate != state);
	}
}

class DLext extends DLobj
{
	DLext(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,1);}
	DLext(){super(); init(1,1);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		g.drawLine(bx+WID/4, by+HT/2, bx+WID, by+HT/2);
		if (dlout[0] == null) {
			g.drawLine(bx+WID-WID/8, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx+WID-WID/8, by+HT/8+HT/2, bx+WID, by+HT/2);
		}
	}

}

class DLone extends DLobj
{
	DLone(DLSim theApplet) {super(theApplet); resize(WID,HT); init(0,1); state = 1;}
	DLone(){super(); init(0,1); state = 1;}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawString("1", bx, by+HT/2+g.getFontMetrics().getAscent()/2);
		g.drawLine(bx+WID/3, by+HT/2, bx+WID, by+HT/2);
		if (dlout[0] == null) {
			g.drawLine(bx+WID-WID/8, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx+WID-WID/8, by+HT/8+HT/2, bx+WID, by+HT/2);
		}
	}

	boolean eval(){return false;}
}

class DLzero extends DLobj
{
	DLzero(DLSim theApplet) {super(theApplet); resize(WID,HT); init(0,1); state = 0;}
	DLzero(){super(); init(0,1); state = 0;}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawString("0", bx, by+HT/2+g.getFontMetrics().getAscent()/2);
		g.drawLine(bx+WID/3, by+HT/2, bx+WID, by+HT/2);
		if (dlout[0] == null) {
			g.drawLine(bx+WID-WID/8, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx+WID-WID/8, by+HT/8+HT/2, bx+WID, by+HT/2);
		}
	}

	boolean eval(){return false;}
}

class DLbext extends DLobj
{
	DLbext(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,1);}
	DLbext(){super(); init(1,1);}

	Point cin(int i) {return new Point(bx+WID, by+HT/2);}
	Point cout(int i) {return new Point(bx, by+HT/2);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx+WID-WID/4, by+HT/2, bx+WID, by+HT/2);
		g.setColor(hold);
		g.drawLine(bx, by+HT/2, bx+WID-WID/4, by+HT/2);
		if (dlout[0] == null) {
			g.drawLine(bx, by+HT/2, bx+WID/8, by-HT/8+HT/2);
			g.drawLine(bx, by+HT/2, bx+WID/8, by+HT/8+HT/2);
		}
	}

}

class DLutee extends DLobj
{
	DLutee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
	DLutee(){super(); init(1,2);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		g.drawLine(bx+WID/4, by+HT/2, bx+WID, by+HT/2);
		g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by);
		if (dlout[0] == null) {
			g.drawLine(bx+WID-WID/8, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx+WID-WID/8, by+HT/8+HT/2, bx+WID, by+HT/2);
		}
		if (dlout[1] == null) {
			g.drawLine(bx-WID/8+WID/2, by+HT/8, bx+WID/2, by);
			g.drawLine(bx+WID/8+WID/2, by+HT/8, bx+WID/2, by);
		}

	}

	int whichOut(int x, int y) 
	{
		if (y <= (HT/WID)*(bx - x) + by + HT) return 1;
		return 0;
	}

	Point cout(int k) {
		if (k == 0) return new Point(bx+WID, by+HT/2);
		return new Point(bx+WID/2, by);
	}
}

class DLrtee extends DLobj
{
	DLrtee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
	DLrtee(){super(); init(1,2);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx+WID/2, by+HT, bx+WID/2, by+3*HT/4);
		g.setColor(hold);
		g.drawLine(bx+WID/2, by+3*HT/4, bx+WID/2, by);
		g.drawLine(bx+WID/2, by+HT/2, bx+WID, by+HT/2);
		if (dlout[0] == null) {
			g.drawLine(bx+WID/2-WID/8, by+HT/8, bx+WID/2, by);
			g.drawLine(bx+WID/2+WID/8, by+HT/8, bx+WID/2, by);
		}
		if (dlout[1] == null) {
			g.drawLine(bx-WID/8+WID, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx-WID/8+WID, by+HT/8+HT/2, bx+WID, by+HT/2);
		}

	}

	int whichOut(int x, int y) 
	{
		if (y <= (HT/WID)*(bx - x) + by + HT) return 0;
		return 1;
	}

	Point cin(int i) {return new Point(bx+WID/2, by+HT);}

	Point cout(int k) {
		if (k == 0) return new Point(bx+WID/2, by);
		return new Point(bx+WID, by+HT/2);
	}
}

class DLdtee extends DLobj
{
	DLdtee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
	DLdtee(){super(); init(1,2);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		g.drawLine(bx+WID/4, by+HT/2, bx+WID, by+HT/2);
		g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by+HT);
		if (dlout[0] == null) {
			g.drawLine(bx+WID-WID/8, by-HT/8+HT/2, bx+WID, by+HT/2);
			g.drawLine(bx+WID-WID/8, by+HT/8+HT/2, bx+WID, by+HT/2);
		}
		if (dlout[1] == null) {
			g.drawLine(bx-WID/8+WID/2, by+HT-HT/8, bx+WID/2, by+HT);
			g.drawLine(bx+WID/8+WID/2, by+HT-HT/8, bx+WID/2, by+HT);
		}

	}

	int whichOut(int x, int y) 
	{
		if (y <= (HT/WID)*(x - bx) + by) return 0;
		return 1;
	}

	Point cout(int k) {
		if (k == 0) return new Point(bx+WID, by+HT/2);
		return new Point(bx+WID/2, by+HT);
	}

}

interface Labelable
{
	public void getLabel();
	public void putLabel(String theLabel);
	public String myLabel();
	public int bx();
	public int by();
}

class DLswitch extends DLobj implements Labelable
{
	String theLabel = null;

	DLswitch(DLSim theApplet) {super(theApplet); resize(WID,HT); init(0,1); state = 0;}
	DLswitch(){super(); init(0,1); state = 0;}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawLine(bx+WID/4, by+HT/4, bx+WID-WID/3, by+HT/4);
		g.drawLine(bx+WID-WID/3, by+HT/4, bx+WID, by+HT/2);
		g.drawLine(bx+WID/4, by+HT-HT/4, bx+WID-WID/3, by+HT-HT/4);
		g.drawLine(bx+WID-WID/3, by+HT-HT/4, bx+WID, by+HT/2);
		g.drawLine(bx+WID/4, by+HT/4, bx+WID/4, by+HT-HT/4);
		Color hold = g.getColor();
		g.setColor((state == 0) ? OFFCOL : ONCOL);
		g.fillOval(bx+WID/3,by+HT/3,WID-2*WID/3+30/WID,HT-2*HT/3+30/HT);
		g.setColor(hold);
		if (theLabel != null) {
			Font OldFnt = g.getFont();
			g.setFont(new Font("Arial", Font.ITALIC, 9));
			g.drawString(theLabel, bx, by+g.getFontMetrics().getAscent());
			g.setFont(OldFnt);
		}
	}

	int whichIn(int x, int y) {return -1;}

	boolean eval(){return false;}
	public int bx(){return bx;}
	public int by(){return by;}

	public void putLabel(String theLabel){this.theLabel = theLabel;}
	public String myLabel(){return this.theLabel;}
	public void getLabel()
	{
		try {
			Thread.sleep(200);
		} catch (Exception e) {}
		new LDialog(theApplet, this).show();
	}
}

class DLbulb extends DLobj implements Labelable
{
	String theLabel = null;

	DLbulb(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,0);}
	DLbulb(){super(); init(1,0);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawLine(bx+WID/3, by+HT/4, bx+WID-WID/4, by+HT/4);
		g.drawLine(bx, by+HT/2, bx+WID/3, by+HT/4);
		g.drawLine(bx+WID/3, by+HT-HT/4, bx+WID-WID/4, by+HT-HT/4);
		g.drawLine(bx, by+HT/2, bx+WID/3, by+HT-HT/4);
		g.drawLine(bx+WID-WID/4, by+HT/4, bx+WID-WID/4, by+HT-HT/4);
		Color hold = g.getColor();
		g.setColor((state == -1) ? DISCOL : (state == 0) ? OFFCOL : ONCOL);
		g.fillOval(bx+WID/3,by+HT/3,WID-2*WID/3+30/WID,HT-2*HT/3+30/HT);
		g.setColor(hold);
		if (theLabel != null) {
			Font OldFnt = g.getFont();
			g.setFont(new Font("Arial", Font.ITALIC, 9));
			g.drawString(theLabel, bx, by+g.getFontMetrics().getAscent());
			g.setFont(OldFnt);
		}
	}

	int whichOut(int x, int y) {return -1;}

	public int bx(){return bx;}
	public int by(){return by;}

	public void putLabel(String theLabel){this.theLabel = theLabel;}
	public String myLabel(){return this.theLabel;}
	public void getLabel()
	{
		try {
			Thread.sleep(200);
		} catch (Exception e) {}
		new LDialog(theApplet, this).show();
	}
}

class DLlabel extends DLobj implements Labelable
{
	String theLabel = "Label";
	LDialog dlg;

	DLlabel(String theLabel, DLSim theApplet)
	{super(theApplet); resize(WID,HT); init(0,0); this.theLabel = theLabel;}
	DLlabel(DLSim theApplet) {super(theApplet); resize(WID,HT); init(0,0);}
	DLlabel(){super(); init(0,0);}

	int whichOut(int x, int y) {return -1;}
	int whichIn(int x, int y) {return -1;}

	boolean eval(){return false;}

	public int bx(){return bx;}
	public int by(){return by;}

	public void putLabel(String theLabel){this.theLabel = theLabel;}
	public String myLabel(){return this.theLabel;}
	public void getLabel()
	{
		try {
			Thread.sleep(200);
		} catch (Exception e) {}
		new LDialog(theApplet, this).show();
	}
	
	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		if (theLabel == null || theLabel.length() == 0) g.drawRect(bx, by, WID-1, HT-1);
		g.drawString(theLabel, bx+WID/20, by+3*HT/5);
	}
}

class DLadd extends DLobj
{
	int carry = -1;

	DLadd(DLSim theApplet) {super(theApplet); resize(WID,HT); init(3,2);}
	DLadd(){super(); init(3,2);}

	protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
	{
		g.drawRect(bx+WID/4, by, WID/2, HT);
		Color hold = g.getColor();
		if (inHilite[0]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/4, bx+WID/4, by+HT/4);
		g.setColor(hold);
		if (inHilite[1]) g.setColor(INHILITE);
		g.drawLine(bx, by+HT/2, bx+WID/4, by+HT/2);
		g.setColor(hold);
		if (inHilite[2]) g.setColor(INHILITE);
		g.drawLine(bx, by+3*HT/4, bx+WID/4, by+3*HT/4);
		g.setColor(hold);
		Font OldFnt = g.getFont();
		g.setFont(new Font("Arial", Font.PLAIN, 9));
		if (WID == DLobj.IWID) g.drawString("A", bx+WID/3, by+HT/2);
		else {
			g.drawString("Add", bx+WID/3, by+HT/2);
			g.setFont(new Font("Arial", Font.ITALIC, 9));
			g.drawString("x", bx, by+HT/4-2);
			g.drawString("y", bx, by+HT/2-2);
			g.drawString("c", bx, by+3*HT/4-2);
			g.drawString("s", bx+3*WID/4+5, by+HT/3-2);
			g.drawString("c", bx+3*WID/4+5, by+2*HT/3-2);
		}
		g.setFont(OldFnt);
		g.drawLine(bx+3*WID/4, by+HT/3, bx+WID, by+HT/3);
		g.drawLine(bx+WID-WID/4, by+2*HT/3, bx+WID, by+2*HT/3);
	}

	int whichOut(int x, int y) {return (y < by+HT/2) ? 0 : 1;}

	Point cout(int k) {
		if (k == 0) return new Point(bx+WID, by+HT/3);
		return new Point(bx+WID, by+2*HT/3);
	}

	boolean eval()
	{
		int oldstate = state;
		int in0 = (dlin[0] == null) ? -1 : dlin[0].stateOf(dlinout[0]);
		int in1 = (dlin[1] == null) ? -1 : dlin[1].stateOf(dlinout[1]);
		int in2 = (dlin[2] == null) ? -1 : dlin[2].stateOf(dlinout[2]);
		if (in0 == -1) {
			if (in1 == -1) {state = in2; carry = 0;}
			else if (in2 == -1) {state = in1; carry = 0;}
			else {state = in1 ^ in2; carry = in1 & in2;}
		} else if (in1 == -1) {
			if (in2 == -1) {state = in0; carry = 0;}
			else {state = in0 ^ in2; carry = in0 & in2;}
		} else if (in2 == -1) {state = in1 ^ in2; carry = in1 & in2;}
		else {state = in0 ^ in1 ^ in2; carry = (in0 & in1) | (in1 & in2) | (in0 & in2);}
		return (oldstate != state);
	}

	int stateOf(int n) {return (n == 0) ? state : carry;}
}


class CPanel extends Panel
{
	public void paint(Graphics g)
	{
		super.paint(g);
		g.drawRect(0,0,size().width-1,size().height-1);
	}
}

class DCanvas extends Canvas
{
	final static int NEUTRAL = 0;
	final static int MOVE = 1;
	final static int CONNECT = 2;
	final static Color BKCOL = Color.white;
	final static Color SBKCOL = Color.black;
	int mode;
	Vector objlist;
	DLobj current = null;
	int currentOut = 0;
	DLobj oldInHilite = null;
	int drag_x;
	int drag_y;
	DLSim theApplet;

	DCanvas(DLSim theApplet)
	{
		super();
		setBackground(BKCOL);
		mode = NEUTRAL;
		this.theApplet = theApplet;
		objlist = new Vector();
	}

	void unserialize(InputStream in)
	{
		DataInputStream din = new DataInputStream(in);
		Vector sobjlist = new Vector();
		try {
			while (in.available() > 0) {
				String s = din.readLine();
				sobjlist.addElement(s);
			}
		} catch (IOException e) {return;}
		unserialize(sobjlist);
	}

	void unserialize(Vector sobjlist)
	{
		Vector lobjlist = new Vector();		
		objlist = new Vector();
		for (int i = 0; i < sobjlist.size(); i++) {
			StringTokenizer st = 
				new StringTokenizer((String)sobjlist.elementAt(i), ",\t\n\r");
			DLobj newobj = null;
			try {
				String s = st.nextToken();
				newobj = (DLobj)Class.forName(s).newInstance();
				newobj.theApplet = theApplet;
				s = st.nextToken();
				newobj.state = Integer.parseInt(s);
				s = st.nextToken();
				newobj.bx = Integer.parseInt(s);
				s = st.nextToken();
				newobj.by = Integer.parseInt(s);
				for (int j = 0; j < newobj.dlin.length; j++) {
					s = st.nextToken();
					newobj.dlinout[j] = Integer.parseInt(s);
				}
				for (int j = 0; j < newobj.dlout.length; j++) {
					s = st.nextToken();
					newobj.dloutin[j] = Integer.parseInt(s);
				}
				if (newobj instanceof Labelable) {
					s = st.nextToken();
					if (s.compareTo("null") == 0) ((Labelable)newobj).putLabel(null);
					else ((Labelable)newobj).putLabel(s);
				}
			} catch (Exception e) {System.out.println(e);}
			lobjlist.addElement(newobj);
		}
		for (int i = 0; i < sobjlist.size(); i++) {
			DLobj target = (DLobj)lobjlist.elementAt(i);
			if (target == null) continue;
			for (int j = 0; j < target.dlin.length; j++) {
				if (target.dlinout[j] == -1) continue;
				DLobj source = (DLobj)lobjlist.elementAt(target.dlinout[j]); 
				int k;
				for (k = 0; k < source.dlout.length; k++)
					if (source.dloutin[k] == i) break;
				if (k == source.dlout.length) continue;
				target.dlin[j] = source;
				target.dlinout[j] = k;
				source.dlout[k] = target;
				source.dloutin[k] = j;
			}
		}
		objlist = lobjlist;
		repaint();
	}

	void serializeAll(PrintStream fp)
	{
		for (int i = 0; i < objlist.size(); i++) {
			DLobj theobj = (DLobj)objlist.elementAt(i);
			if (theobj != null) fp.println(theobj.serialize());
		}
	}

	public void paint(Graphics g)
	{
		g.drawRect(0,0,size().width-1,size().height-1);
		for (int i = 0; i < objlist.size(); i++) {
			DLobj theobj = (DLobj)objlist.elementAt(i);
			if (theobj == null) continue;
			Color hold = g.getColor();
			if (theApplet.simmode == theApplet.SIMON)
				g.setColor((theobj.state == -1) ? DLobj.DISCOL :
						   (theobj.state == 0) ? DLobj.OFFCOL : DLobj.ONCOL);
			theobj.cpaint(g);
			g.setColor(hold);
		}
		for (int i = 0; i < objlist.size(); i++) {
			DLobj source = (DLobj)objlist.elementAt(i);
			if (source == null) continue;
			for (int j = 0; j < source.dlout.length; j++) {
				DLobj target = source.dlout[j];
				if (target != null) {
					Color hold = g.getColor();
					if (theApplet.simmode == theApplet.SIMON)
						g.setColor((source.state == -1) ? DLobj.DISCOL :
								   (source.state == 0) ? DLobj.OFFCOL : DLobj.ONCOL);
					g.drawLine(source.cout(j).x, source.cout(j).y, 
						       target.cin(source.dloutin[j]).x, target.cin(source.dloutin[j]).y);
					g.setColor(hold);
				}
			}
		}
		if (mode == CONNECT && current != null) {
			Color hold = g.getColor();
			if (theApplet.simmode == theApplet.SIMON) 
				g.setColor((current.state == -1) ? DLobj.DISCOL :
						   (current.state == 0) ? DLobj.OFFCOL : DLobj.ONCOL);
			g.drawLine(current.cout(currentOut).x, current.cout(currentOut).y, drag_x, drag_y);
			g.setColor(hold);
		}
	}

	// MOUSE SUPPORT:
	//		The mouseDown() method is called if the mouse button is pressed
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseDown(Event evt, int x, int y)
	{
		DLobj theobj;

		if (current != null) return true;
		if ((theobj = dlobjAt(x,y)) == null) return true;
		mode = ((evt.modifiers & Event.META_MASK) != 0) ? CONNECT : MOVE;
		current = theobj;
		if (evt.clickCount > 1) System.out.println(theobj.serialize());
		drag_x = x;
		drag_y = y;
		if (mode == MOVE && current instanceof DLswitch){
			Rectangle brect = 
				new Rectangle(current.bx+DLobj.WID/3,current.by+DLobj.HT/3,
						      DLobj.WID-2*DLobj.WID/3+30/DLobj.WID,
							  DLobj.HT-2*DLobj.HT/3+30/DLobj.HT);
			if (brect.inside(x,y)) {
				current.state = 1 - current.state;
				mode = NEUTRAL;
				current = null;
				repaint(brect.x, brect.y, brect.width, brect.height);
				Thread m_sim = new Thread(new Simulate(theApplet));
				m_sim.start();
				return true;
			} 
		}
		if (mode == CONNECT) {
			if (current instanceof DLswitch || current instanceof DLbulb) {
				Rectangle lrect = new Rectangle(current.bx, current.by, DLobj.WID, DLobj.HT/3);
				if (lrect.inside(x,y)) {
					if (current instanceof DLswitch) ((DLswitch)current).getLabel();
					else ((DLbulb)current).getLabel();
					current = null;
					mode = NEUTRAL;
					return true;
				}
			}
			if (current instanceof DLlabel) {
				((DLlabel)current).getLabel();
				current = null;
				mode = NEUTRAL;
				return true;
			}
			if ((currentOut = current.whichOut(x, y)) < 0) {
				mode = NEUTRAL;
				current = null;
				return true;
			}
			if (current.dlout[currentOut] != null) {
				DLobj target = current.dlout[currentOut];
				for (int j = 0; j < target.dlin.length; j++)
					if (target.dlin[j] == current) target.dlin[j] = null;
				current.dlout[currentOut] = null;
				Thread m_sim = new Thread(new Simulate(theApplet));
				m_sim.start();
			}
		}
		repaint();
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseUp() method is called if the mouse button is released
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseUp(Event evt, int x, int y)
	{
		if (current == null) return true;
		if (mode == CONNECT) {
			killHilite();
			DLobj target = dlobjAt(x,y);
			if (target != null && target != current) {
				int j = target.whichIn(x, y);
				if (j >= 0) {
					current.dlout[currentOut] = target;
					DLobj oldIn;
					if ((oldIn = target.dlin[j]) != null) oldIn.dlout[target.dlinout[j]] = null;
					target.dlin[j] = current;
					current.dloutin[currentOut] = j;
					target.dlinout[j] = currentOut;
				}
				Thread m_sim = new Thread(new Simulate(theApplet));
				m_sim.start();
			}
		}
		current = null;
		mode = NEUTRAL;
		repaint();
		return true;
	}

	DLobj dlobjAt(int x, int y) 
	{
		for (int i = 0; i < objlist.size(); i++) {
			DLobj theobj = (DLobj)objlist.elementAt(i);
			if (theobj == null) continue;
			if (x >= theobj.bx && x <= theobj.bx+DLobj.WID
				&& y >= theobj.by && y <= theobj.by+DLobj.HT) 
				return theobj;
		}	
		return null;
	}

	void killHilite()
	{
		if (oldInHilite != null) 
			for (int j = 0; j < oldInHilite.dlin.length; j++)
					oldInHilite.inHilite[j] = false;
	}

	// MOUSE SUPPORT:
	//		The mouseDrag() method is called if the mouse cursor moves over the
	// applet's portion of the screen while the mouse button is being held down.
	//--------------------------------------------------------------------------
	public boolean mouseDrag(Event evt, int x, int y)
	{
		if (current != null){
			if (mode == CONNECT) {
				Rectangle clrect = new Rectangle(current.cout(currentOut));
				clrect.add(new Point(drag_x, drag_y));
				drag_x = x;
				drag_y = y;
				clrect.add(new Point(drag_x, drag_y));
				DLobj target = dlobjAt(x, y);
				killHilite();
				if (target != null && target != current && target.dlin.length > 0) {
					target.inHilite[target.whichIn(x,y)] = true;
					oldInHilite = target;
				}
				repaint(clrect.x-DLobj.WID/2, clrect.y-DLobj.HT/2, 
						clrect.width+DLobj.WID, clrect.height+DLobj.HT);
				return true;
			}
			int dx = x - drag_x;
			int dy = y - drag_y;
			drag_x = x;
			drag_y = y;
			int oldbx = current.bx;
			int oldby = current.by;
			current.bx += dx;
			current.by += dy;
			int sx = Math.min(oldbx, current.bx) - 2;
			int sy = Math.min(oldby, current.by) - 2;
			int lx = Math.max(oldbx, current.bx) + DLobj.WID + 2;
			int ly = Math.max(oldby, current.by) + DLobj.HT + 2;
			Rectangle clrect = new Rectangle(sx, sy, lx-sx, ly-sy);
			for (int i = 0; i < current.dlin.length; i++)
				if (current.dlin[i] != null) 
					clrect.add(current.dlin[i].cout(current.dlinout[i]));
			for (int i = 0; i < current.dlout.length; i++)
				if (current.dlout[i] != null) 
					clrect.add(current.dlout[i].cin(current.dloutin[i]));
			repaint(clrect.x-DLobj.WID/2, clrect.y-DLobj.HT/2, 
						clrect.width+DLobj.WID, clrect.height+DLobj.HT);
		}
		return true;
	}

	

	// MOUSE SUPPORT:
	//		The mouseMove() method is called if the mouse cursor moves over the
	// applet's portion of the screen and the mouse button isn't being held down.
	//--------------------------------------------------------------------------
	public boolean mouseMove(Event evt, int x, int y)
	{
		return false;
	}

	// MOUSE SUPPORT:
	//		The mouseEnter() method is called if the mouse cursor enters the
	// applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseEnter(Event evt, int x, int y)
	{
		// TODO: Place applet mouseEnter code here
//		if (current == null) theApplet.myFrame.setCursor(Frame.CROSSHAIR_CURSOR);
//		else theApplet.myFrame.setCursor(Frame.MOVE_CURSOR);
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseExit() method is called if the mouse cursor leaves the
	// applet's portion of the screen.
 	//--------------------------------------------------------------------------
	public boolean mouseExit(Event evt, int x, int y)
	{
		if (current != null && mode == MOVE) {
			objlist.removeElement(current);
			for (int i = 0; i < objlist.size(); i++) {
				DLobj theobj = (DLobj)objlist.elementAt(i);
				if (theobj == null) continue;
				for (int j = 0; j < theobj.dlout.length; j++)
					if (theobj.dlout[j] == current) theobj.dlout[j] = null;
			}
			current = null;
			Thread m_sim = new Thread(new Simulate(theApplet));
			m_sim.start();
			repaint();
		}
		return true;
	}


	// TODO: Place additional applet code here

}
