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 int MAXPIN = 4;
  final static Color INHILITE = Color.red;
  final static Color OUTHILITE = Color.red;
  final static Color DISCOL = Color.lightGray;
  final static Color ONCOL = Color.yellow;
  final static Color OFFCOL = Color.blue;

  int state = -1;
  int WIDTH = DLobj.WID;
  int HTH = DLobj.HT;
  int bx = 0;
  int by = 0;
  DLobj dlin[], dlout[];
  int[] dloutin, dlinout;
  DLSim theApplet;
  boolean[] inHilite;
  boolean[] outHilite;

  DLobj() {this.theApplet = null;}
  DLobj(DLSim theApplet){this.theApplet = theApplet; resize(IWID,IHT);}
  public void paint(Graphics g) {cpaint(0,0,IWID,IHT,g);}
  void cpaint(Graphics g) {cpaint(bx,by,this.WIDTH,this.HTH,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) {
    dlin = new DLobj[vin];
    dlout = new DLobj[vout];
    dlinout = new int[vin];
    dloutin = new int[vout];
    inHilite = new boolean[vin];
    outHilite = new boolean[vout];
  }

  int whichIn(int x, int y) 
  {
    for (int j = 0; j < dlin.length; j++)
      if (y <= by+(j+1)*HTH/(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)*HTH/(dlin.length+1));}
  Point cout(int i) {
    return new Point(bx+WIDTH, by+(i+1)*HTH/(dlout.length+1));
  }

  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;
  }

  int isClock()
  {
    if (!(this instanceof DLswitch)) return -1;
    if (((DLswitch)this).myLabel().compareTo(">") == 0) return 1;
    if (((DLswitch)this).myLabel().compareTo("<") == 0) return 0;
    return -1;
  }
}

class DLabs extends DLobj implements Labelable
{
  Vector lobjlist;
  DLobj[] inref, outref;
  String name = "";
  DLswitch clockin = null;
  boolean synched = false;

  DLabs() {
    super();
    init();
  }

  void init() {
    WIDTH = 2 * DLobj.WID; HTH = 2 * DLobj.HT;
    int maxpin = Math.max(inref.length, outref.length);
    if (maxpin > MAXPIN) HTH += 10 * (maxpin - MAXPIN);
    int nameWidth =
      getFontMetrics(new Font("Arial", Font.PLAIN, 12)).stringWidth(name);
    if (nameWidth > WIDTH/2) WIDTH += nameWidth + 8 - WIDTH/2;
    init(inref.length, outref.length);
  }

  DLabs(Vector sobjlist, DLSim theApplet, String name, String d)
  {
    super(theApplet);
    this.name = name;
    lobjlist = theApplet.pegboard.unserialize(sobjlist, d);
    int incnt = 0, outcnt = 0;
    for (int i = 0; i < lobjlist.size(); i++) {
      if (lobjlist.elementAt(i) instanceof DLswitch) {
	incnt++;
	if (clockin == null && ((DLobj)lobjlist.elementAt(i)).isClock() != -1)
	  clockin = (DLswitch)lobjlist.elementAt(i);
      }
      if (lobjlist.elementAt(i) instanceof DLbulb) outcnt++;
    }
    init(incnt, outcnt);
    inref = new DLobj[incnt];
    outref = new DLobj[outcnt];
    incnt = 0; outcnt = 0;
    try {
      for (int i = 0; i < lobjlist.size(); i++) {
	if (lobjlist.elementAt(i) instanceof DLswitch) 
	  inref[incnt++] = (DLobj)lobjlist.elementAt(i);
	if (lobjlist.elementAt(i) instanceof DLbulb) 
	  outref[outcnt++] = (DLobj)lobjlist.elementAt(i);
      }
    }catch (Exception e) {System.out.println(e);}
  }

  protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
  {
    String temp;
	Color hold = g.getColor();
    g.drawRect(bx+WID/4, by, WID/2, HT);
    int w = HT/(inref.length+1);
    for (int i = 0; i < inref.length; i++) {
      if (inHilite[i]) g.setColor(INHILITE);
      g.drawLine(bx, by+(i+1)*w,  bx+WID/4, by+(i+1)*w);
      g.setColor(hold);
      if ((temp = ((Labelable)inref[i]).myLabel()) != null) {
	Font OldFnt = g.getFont();
	g.setFont(new Font("Arial", Font.ITALIC, 9));
	g.drawString(temp, bx, by+(i+1)*w-2);
	g.setFont(OldFnt);
      }
    }
    w = HT/(outref.length+1);
    for (int i = 0; i < outref.length; i++) {
		if (outHilite[i]) g.setColor(OUTHILITE);
      g.drawLine(bx+3*WID/4, by+(i+1)*w, bx+WID, by+(i+1)*w);
	  g.setColor(hold);
      if ((temp = ((Labelable)outref[i]).myLabel()) != null) {
	Font OldFnt = g.getFont();
	g.setFont(new Font("Arial", Font.ITALIC, 9));
	g.drawString(temp, bx+3*WID/4+2, by+(i+1)*w-2);
	g.setFont(OldFnt);
      }
    }
    FontMetrics fm = g.getFontMetrics();
    g.drawString(name, bx+WID/2-fm.stringWidth(name)/2, by+HT/2);
  }

  int whichOut(int x, int y) 
  {
    for (int j = 0; j < dlout.length; j++)
      if (y <= by+(j+1)*HTH/(dlout.length)) return j;
    return -1;
  }

  int stateOf(int i) {return outref[i].stateOf(0);}

  boolean eval()
  {
    int[] states = new int[outref.length];
    for (int i = 0; i < outref.length; i++) states[i] = stateOf(i);
    for (int i = 0; i < dlin.length; i++)
      inref[i].state = 
	(dlin[i] == null) ? -1 : dlin[i].stateOf(dlinout[i]);
    if (clockin != null) {
      if (clockin.state == clockin.isClock()) {
	if (synched) return false;
	synched = true;
      } else {
	synched = false;
        return false;
      }
    }
    Simulate.evalLoop(lobjlist);
    if (clockin != null) 
      for (int i = 0; i < lobjlist.size(); i++) 
	if (lobjlist.elementAt(i) instanceof DLabs) 
	  ((DLabs)lobjlist.elementAt(i)).synched = false;
    for (int i = 0; i < outref.length; i++) 
      if (states[i] != stateOf(i)) return true;
    return false;
  }

  public int bx(){return bx;}
  public int by(){return by;}

  public void putLabel(String name){this.name = name;}
  public String myLabel(){return this.name;}
  public void getLabel(){};
}

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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
	g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/8, by+HT/2, bx+WID, by+HT/2);
    g.setColor(hold);
  }

  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); WIDTH = WID/2; HTH = 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, by+HT/2, bx+WID/2, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, 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);
    }
    g.setColor(hold);
  }

}

class DLone extends DLobj
{
  DLone(DLSim theApplet) {super(theApplet); resize(WID,HT); init(0,1); state = 1;}
  DLone(){super(); init(0,1); state = 1; WIDTH = WID/2; HTH = HT/2;}

  protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
  {
    Color hold = g.getColor();
    g.drawString("1", bx, by+HT/2+g.getFontMetrics().getAscent()/2);
    g.drawLine(bx+WID/3, by+HT/2, bx+3*WID/4, by+HT/2);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+3*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);
    }
    g.setColor(hold);
  }

  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; WIDTH = WID/2; HTH = HT/2;}

  protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
  {
    Color hold = g.getColor();
    g.drawString("0", bx, by+HT/2+g.getFontMetrics().getAscent()/2);
    g.drawLine(bx+WID/3, by+HT/2, bx+3*WID/4, by+HT/2);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+3*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);
    }
    g.setColor(hold);
  }

  boolean eval(){return false;}
}

class DLbext extends DLobj
{
  DLbext(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,1);}
  DLbext(){super(); init(1,1); WIDTH = WID/2; HTH = HT/2;}

  Point cin(int i) {return new Point(bx+WIDTH, by+HTH/2);}
  Point cout(int i) {return new Point(bx, by+HTH/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/2, bx+WID, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx, by+HT/2, bx+WID/2, 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);
    }
    g.setColor(hold);
  }

}

class DLutee extends DLobj
{
  DLutee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
  DLutee(){super(); init(1,2); WIDTH = WID/2; HTH = 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, by+HT/2, bx+WID/2, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    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);
    }
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by);
    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 <= (HTH/WIDTH)*(bx - x) + by + HTH) return 1;
    return 0;
  }

  Point cout(int k) {
    if (k == 0) return new Point(bx+WIDTH, by+HTH/2);
    return new Point(bx+WIDTH/2, by);
  }
}

class DLrtee extends DLobj
{
  DLrtee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
  DLrtee(){super(); init(1,2); WIDTH = WID/2; HTH = 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/2, by+HT, bx+WID/2, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by);
    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);
    }
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID, by+HT/2);
    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);
    }
    g.setColor(hold);
  }

  int whichOut(int x, int y) 
  {
    if (y <= (HTH/WIDTH)*(bx - x) + by + HTH) return 0;
    return 1;
  }

  Point cin(int i) {return new Point(bx+WIDTH/2, by+HTH);}

  Point cout(int k) {
    if (k == 0) return new Point(bx+WIDTH/2, by);
    return new Point(bx+WIDTH, by+HTH/2);
  }
}

class DLrdtee extends DLobj
{
  DLrdtee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
  DLrdtee(){super(); init(1,2); WIDTH = WID/2; HTH = 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/2, by, bx+WID/2, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by+HT);
    if (dlout[0] == null) {
      g.drawLine(bx+WID/2-WID/8, by+HT-HT/8, bx+WID/2, by+HT);
      g.drawLine(bx+WID/2+WID/8, by+HT-HT/8, bx+WID/2, by+HT);
    }
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID, by+HT/2);
    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);
    }
    g.setColor(hold);
  }

  int whichOut(int x, int y) 
  {
    if (y >= by+2*HTH/3) return 0;
    return 1;
  }

  Point cin(int i) {return new Point(bx+WIDTH/2, by);}

  Point cout(int k) {
    if (k == 0) return new Point(bx+WIDTH/2, by+HTH);
    return new Point(bx+WIDTH, by+HTH/2);
  }
}

class DLdtee extends DLobj
{
  DLdtee(DLSim theApplet) {super(theApplet); resize(WID,HT); init(1,2);}
  DLdtee(){super(); init(1,2); WIDTH = WID/2; HTH = 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, by+HT/2, bx+WID/2, by+HT/2);
    g.setColor(hold);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, 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);
    }
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID/2, by+HT/2, bx+WID/2, by+HT);
    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);
    }
    g.setColor(hold);
  }

  int whichOut(int x, int y) 
  {
    if (y <= (HTH/WIDTH)*(x - bx) + by) return 0;
    return 1;
  }

  Point cout(int k) {
    if (k == 0) return new Point(bx+WIDTH, by+HTH/2);
    return new Point(bx+WIDTH/2, by+HTH);
  }

}

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)
  {
    Color hold = g.getColor();
	g.drawLine(bx+WID/4, by+HT/4, bx+WID-WID/3, by+HT/4);
    g.drawLine(bx+WID/4, by+HT-HT/4, bx+WID-WID/3, by+HT-HT/4);
	if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/3, by+HT/4, bx+WID, by+HT/2);
    g.drawLine(bx+WID-WID/3, by+HT-HT/4, bx+WID, by+HT/2);
    g.setColor(hold);
    g.drawLine(bx+WID/4, by+HT/4, bx+WID/4, by+HT-HT/4);
    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);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+3*WID/4, by+HT/3, bx+WID, by+HT/3);
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+WID-WID/4, by+2*HT/3, bx+WID, by+2*HT/3);
    g.setColor(hold);
  }

  int whichOut(int x, int y) {return (y < by+HTH/2) ? 0 : 1;}

  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 = in0 ^ in1; carry = in0 & in1;}
    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 DLclock extends DLobj implements Runnable
{
  boolean ON = false;
  int speed = 2000;
  Thread me = null;

  DLclock(DLSim theApplet)
  {super(theApplet); resize(WID,HT); init(0,2); state = 0;}
  DLclock(){super(); WIDTH = 3*DLobj.WID/2; HTH = 3*DLobj.HT/2;
  init(0,2); state = 0;}

  protected void finalize() throws Throwable 
  {
    super.finalize();
    if (me != null) me.destroy();
  }

  int stateOf(int n) {return (n == 0) ? state : 1 - state;}
  int whichOut(int x, int y) {return (y < by+HTH/2) ? 0 : 1;}

  void toggle() {
    ON = !ON;
    if (ON && me == null) {
      me = new Thread(this);
      me.start();
    }
  }

  public void getSpeed()
  {
    try {
      Thread.sleep(200);
    } catch (Exception e) {}
    new CDialog(theApplet, this).show();
  }

  public void run()
  {
    try {
      while (ON) {
	Thread.sleep(speed/2);
	state = 1 - state;
	Thread m_sim = new Thread(new Simulate(theApplet));
	m_sim.start();
	theApplet.pegboard.repaint(bx, by, WIDTH, HTH);
      }
    } catch (Exception e) {}
    me = null;
  }

  protected void cpaint(int bx, int by, int WID, int HT, Graphics g)
  {
    Color hold = g.getColor();
	g.drawRect(bx, by, 3*WID/4, HT);
    if (outHilite[0]) g.setColor(OUTHILITE);
    g.drawLine(bx+3*WID/4, by+HT/3,bx+WID, by+HT/3);
    g.setColor(hold);
    if (outHilite[1]) g.setColor(OUTHILITE);
    g.drawLine(bx+3*WID/4, by+2*HT/3,bx+WID, by+2*HT/3);
    g.setColor(hold);
    g.drawLine(bx+WID/11, by+HT/3, bx+2*WID/11, by+HT/3);
    g.drawLine(bx+2*WID/11, by+HT/3, bx+2*WID/11, by-HT/11+HT/3);
    g.drawLine(bx+2*WID/11, by-HT/11+HT/3, bx+3*WID/11, by-HT/11+HT/3);
    g.drawLine(bx+3*WID/11, by-HT/11+HT/3, bx+3*WID/11, by+HT/3);
    g.drawLine(bx+3*WID/11, by+HT/3, bx+4*WID/11, by+HT/3);
    g.setColor((state == 0) ? OFFCOL : ONCOL);
    g.fillOval(bx+WID/2-2,by+HT/4-4,WID/5+30/WID,HT/5+30/HT);
    g.setColor((state == 0) ? ONCOL : OFFCOL);
    g.fillOval(bx+WID/2-2,by+3*HT/4-4,WID/5+30/WID,HT/5+30/HT);
    g.setColor(hold);
    Font oldFont = g.getFont();
    g.setFont(new Font("Arial", Font.PLAIN, 9));
    int sx =
      bx+5*WID/11-g.getFontMetrics().stringWidth(Integer.toString(speed));
    if (WID > IWID)
      g.drawString(Integer.toString(speed)+" ms", sx, by+2*HT/3-5);
  }

  int whichIn(int x, int y) {return -1;}

  boolean eval(){return false;}
}

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;
  boolean gridOn = true;
  int gridSpace = 5;
  Vector objlist;
  DLobj current = null;
  int currentOut = 0;
  DLobj oldInHilite = null;
  DLobj oldOutHilite = null;
  int drag_x;
  int drag_y;
  DLSim theApplet;
  Image myImage;
  Graphics gbit;

  DCanvas(DLSim theApplet)
  {
    super();
    setBackground(BKCOL);
    mode = NEUTRAL;
    this.theApplet = theApplet;
    objlist = new Vector();
  }

  void doImage() 
  {
    myImage = createImage(size().width, size().height);
  }

  static Vector readcct(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 null;}
    return sobjlist;
  }

  Vector unserialize(InputStream in, String d)
  {
    return unserialize(readcct(in), d);
  }

  Vector unserialize(Vector sobjlist, String d)
  {
    Vector lobjlist = 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();
	if (s.compareTo("DLabs") == 0) {
	  while (st.countTokens() > 0) s = st.nextToken();
	  try{
	    FileInputStream in = 
	      new FileInputStream(new File(d, s+"."+DLSimFrame.EXTSN));
	    newobj = new DLabs(readcct(in), theApplet, s, d);
	    ((DLabs)newobj).init();
	    ((DLSimFrame)theApplet.myFrame).addToCirMenu(d, s);
	  } catch (FileNotFoundException e){
	    new MsgDialog(theApplet, "File Not Found",
			  "File not found: "+s+"."+DLSimFrame.EXTSN).show();
	    //	    System.out.println(e+": "+s);
	  }
	  st = 
	    new StringTokenizer((String)sobjlist.elementAt(i), ",\t\n\r");
	  st.nextToken();
	} else {
	  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;
      }
    }
    return lobjlist;
  }

  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 update(Graphics g)
  {
    Graphics gbit = myImage.getGraphics();
    Rectangle r = g.getClipRect();
    gbit.clipRect(r.x, r.y, r.width, r.height);
    Color hold = gbit.getColor();	
    gbit.setColor(getBackground());
    gbit.fillRect(0,0,size().width-1,size().height-1);
    gbit.setColor(Color.black);
    paint(gbit);
    g.drawImage(myImage, 0, 0, this);
  }

  public void paint(Graphics g)
  {
    Color hold;
    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;
      hold = g.getColor();
      if (theApplet.simmode == theApplet.SIMON) {
	int temp;
	if (theobj.dlout.length <= 1) temp = theobj.stateOf(0); 
	else {
	  temp = -1;
	  for (int j = 0; j < theobj.dlout.length; j++)
	    temp = Math.max(temp, theobj.stateOf(j));
	}
	  g.setColor((temp == -1) ? DLobj.DISCOL :
		   (temp == 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) {
	  hold = g.getColor();
	  if (theApplet.simmode == theApplet.SIMON)
	    g.setColor((source.stateOf(j) == -1) ? DLobj.DISCOL :
		       (source.stateOf(j) == 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) {
      hold = g.getColor();
      if (theApplet.simmode == theApplet.SIMON) 
	g.setColor((current.stateOf(currentOut) == -1) ? DLobj.DISCOL :
		   (current.stateOf(currentOut) == 0) ? DLobj.OFFCOL :
		   DLobj.ONCOL);
      g.drawLine(current.cout(currentOut).x,
		 current.cout(currentOut).y, drag_x, drag_y);
      g.setColor(hold);
    }
  }

  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+current.WIDTH/3,current.by+current.HTH/3,
		      current.WIDTH-2*current.WIDTH/3+30/current.WIDTH,
		      current.HTH-2*current.HTH/3+30/current.HTH);
      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 == MOVE && current instanceof DLclock){
      Rectangle brect = 
	new Rectangle(current.bx+current.WIDTH/2,current.by+current.HTH/4,
		      current.WIDTH/4, 2*current.HTH/3);
      if (brect.inside(x,y)) {
	((DLclock)current).toggle();
	mode = NEUTRAL;
	current = null;
	repaint(brect.x, brect.y, brect.width, brect.height);
	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 DLclock) {
	Rectangle lrect =
	  new Rectangle(current.bx+current.WIDTH/2,current.by+current.HTH/4,
			current.WIDTH/4, 2*current.HTH/3);
	if (lrect.inside(x,y)) {
	  ((DLclock)current).getSpeed();
	  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;
  }

  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();
      }
    } else {
      if (gridOn) {
	int nbx = (current.bx/gridSpace) * gridSpace;
	int nby = (current.by/gridSpace) * gridSpace;
	current.bx = nbx + ((current.bx - nbx > gridSpace/2) ? gridSpace : 0);
	current.by = nby + ((current.by - nby > gridSpace/2) ? gridSpace : 0);
      }
    }
    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+theobj.WIDTH
	  && y >= theobj.by && y <= theobj.by+theobj.HTH) 
	return theobj;
    }	
    return null;
  }

  void killHilite()
  {
    if (oldInHilite != null) 
      for (int j = 0; j < oldInHilite.dlin.length; j++)
	oldInHilite.inHilite[j] = false;
    if (oldOutHilite != null) 
      for (int j = 0; j < oldOutHilite.dlout.length; j++)
	oldOutHilite.outHilite[j] = false;
  }

  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) + current.WIDTH + 2;
      int ly = Math.max(oldby, current.by) + current.HTH + 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;
  }

  public boolean mouseMove(Event evt, int x, int y)
  {
    DLobj target = dlobjAt(x, y);
    killHilite();    
    if (target != null && target.dlout.length > 0) {
      target.outHilite[target.whichOut(x,y)] = true;
      Rectangle crect =
	new Rectangle(target.bx, target.by, target.WIDTH, target.HTH);
      if (oldOutHilite != null) 
	crect.add (new Rectangle(oldOutHilite.bx, oldOutHilite.by,
				 oldOutHilite.WIDTH, oldOutHilite.HTH));
      oldOutHilite = target;
      repaint(crect.x, crect.y, crect.width, crect.height);
    } else if (oldOutHilite != null) 
		repaint(oldOutHilite.bx, oldOutHilite.by,
			oldOutHilite.WIDTH, oldOutHilite.HTH);
    return true;
  }

  public boolean mouseEnter(Event evt, int x, int y)
  {
    return true;
  }

  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

}
