com.lushprojects.circuitjs1.client.element.CirSim.java Source code

Java tutorial

Introduction

Here is the source code for com.lushprojects.circuitjs1.client.element.CirSim.java

Source

/*    
Copyright (C) Paul Falstad and Iain Sharp
    
This file is part of CircuitJS1.
    
CircuitJS1 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
    
CircuitJS1 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with CircuitJS1.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.lushprojects.circuitjs1.client.element;

// GWT conversion (c) 2015 by Iain Sharp

// For information about the theory behind this, see Electronic Circuit & System Simulation Methods by Pillage

import java.util.Random;
import java.util.Vector;
import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window.Navigator;
import com.lushprojects.circuitjs1.client.element.active.AnalogSwitch2Elm;
import com.lushprojects.circuitjs1.client.element.active.AnalogSwitchElm;
import com.lushprojects.circuitjs1.client.element.active.CC2Elm;
import com.lushprojects.circuitjs1.client.element.active.CC2NegElm;
import com.lushprojects.circuitjs1.client.element.active.InvertingSchmittElm;
import com.lushprojects.circuitjs1.client.element.active.OpAmpElm;
import com.lushprojects.circuitjs1.client.element.active.OpAmpSwapElm;
import com.lushprojects.circuitjs1.client.element.active.SchmittElm;
import com.lushprojects.circuitjs1.client.element.active.TriStateElm;
import com.lushprojects.circuitjs1.client.element.digital.CounterElm;
import com.lushprojects.circuitjs1.client.element.digital.DFlipFlopElm;
import com.lushprojects.circuitjs1.client.element.digital.DeMultiplexerElm;
import com.lushprojects.circuitjs1.client.element.digital.DecadeElm;
import com.lushprojects.circuitjs1.client.element.digital.FullAdderElm;
import com.lushprojects.circuitjs1.client.element.digital.HalfAdderElm;
import com.lushprojects.circuitjs1.client.element.digital.JKFlipFlopElm;
import com.lushprojects.circuitjs1.client.element.digital.LatchElm;
import com.lushprojects.circuitjs1.client.element.digital.MonostableElm;
import com.lushprojects.circuitjs1.client.element.digital.MultiplexerElm;
import com.lushprojects.circuitjs1.client.element.digital.PisoShiftElm;
import com.lushprojects.circuitjs1.client.element.digital.SeqGenElm;
import com.lushprojects.circuitjs1.client.element.digital.SevenSegDecoderElm;
import com.lushprojects.circuitjs1.client.element.digital.SevenSegElm;
import com.lushprojects.circuitjs1.client.element.digital.SipoShiftElm;
import com.lushprojects.circuitjs1.client.element.digital.TFlipFlopElm;
import com.lushprojects.circuitjs1.client.element.hybrid.ADCElm;
import com.lushprojects.circuitjs1.client.element.hybrid.DACElm;
import com.lushprojects.circuitjs1.client.element.hybrid.PhaseCompElm;
import com.lushprojects.circuitjs1.client.element.hybrid.TimerElm;
import com.lushprojects.circuitjs1.client.element.hybrid.VCOElm;
import com.lushprojects.circuitjs1.client.element.logic.AndGateElm;
import com.lushprojects.circuitjs1.client.element.logic.InverterElm;
import com.lushprojects.circuitjs1.client.element.logic.LogicInputElm;
import com.lushprojects.circuitjs1.client.element.logic.LogicOutputElm;
import com.lushprojects.circuitjs1.client.element.logic.NandGateElm;
import com.lushprojects.circuitjs1.client.element.logic.NorGateElm;
import com.lushprojects.circuitjs1.client.element.logic.OrGateElm;
import com.lushprojects.circuitjs1.client.element.logic.XorGateElm;
import com.lushprojects.circuitjs1.client.element.output.BoxElm;
import com.lushprojects.circuitjs1.client.element.output.LEDElm;
import com.lushprojects.circuitjs1.client.element.output.LampElm;
import com.lushprojects.circuitjs1.client.element.output.LoudSpeakerElm;
import com.lushprojects.circuitjs1.client.element.output.OutputElm;
import com.lushprojects.circuitjs1.client.element.output.ProbeElm;
import com.lushprojects.circuitjs1.client.element.output.TextElm;
import com.lushprojects.circuitjs1.client.element.passive.Capacitor2Elm;
import com.lushprojects.circuitjs1.client.element.passive.CapacitorElm;
import com.lushprojects.circuitjs1.client.element.passive.InductorElm;
import com.lushprojects.circuitjs1.client.element.passive.MemristorElm;
import com.lushprojects.circuitjs1.client.element.passive.PotElm;
import com.lushprojects.circuitjs1.client.element.passive.PushSwitchElm;
import com.lushprojects.circuitjs1.client.element.passive.RelayElm;
import com.lushprojects.circuitjs1.client.element.passive.ResistorElm;
import com.lushprojects.circuitjs1.client.element.passive.SparkGapElm;
import com.lushprojects.circuitjs1.client.element.passive.Switch2Elm;
import com.lushprojects.circuitjs1.client.element.passive.SwitchElm;
import com.lushprojects.circuitjs1.client.element.passive.TappedTransformerElm;
import com.lushprojects.circuitjs1.client.element.passive.TransLineElm;
import com.lushprojects.circuitjs1.client.element.passive.TransformerElm;
import com.lushprojects.circuitjs1.client.element.semi.DiacElm;
import com.lushprojects.circuitjs1.client.element.semi.DiodeElm;
import com.lushprojects.circuitjs1.client.element.semi.JfetElm;
import com.lushprojects.circuitjs1.client.element.semi.MosfetElm;
import com.lushprojects.circuitjs1.client.element.semi.NJfetElm;
import com.lushprojects.circuitjs1.client.element.semi.NMosfetElm;
import com.lushprojects.circuitjs1.client.element.semi.NTransistorElm;
import com.lushprojects.circuitjs1.client.element.semi.PJfetElm;
import com.lushprojects.circuitjs1.client.element.semi.PMosfetElm;
import com.lushprojects.circuitjs1.client.element.semi.PTransistorElm;
import com.lushprojects.circuitjs1.client.element.semi.SCRElm;
import com.lushprojects.circuitjs1.client.element.semi.TransistorElm;
import com.lushprojects.circuitjs1.client.element.semi.TriacElm;
import com.lushprojects.circuitjs1.client.element.semi.TriodeElm;
import com.lushprojects.circuitjs1.client.element.semi.TunnelDiodeElm;
import com.lushprojects.circuitjs1.client.element.semi.ZenerElm;
import com.lushprojects.circuitjs1.client.element.source.ACRailElm;
import com.lushprojects.circuitjs1.client.element.source.ACVoltageElm;
import com.lushprojects.circuitjs1.client.element.source.AMElm;
import com.lushprojects.circuitjs1.client.element.source.AntennaElm;
import com.lushprojects.circuitjs1.client.element.source.ClockElm;
import com.lushprojects.circuitjs1.client.element.source.CurrentElm;
import com.lushprojects.circuitjs1.client.element.source.DCVoltageElm;
import com.lushprojects.circuitjs1.client.element.source.FMElm;
import com.lushprojects.circuitjs1.client.element.source.GroundElm;
import com.lushprojects.circuitjs1.client.element.source.RailElm;
import com.lushprojects.circuitjs1.client.element.source.SquareRailElm;
import com.lushprojects.circuitjs1.client.element.source.SweepElm;
import com.lushprojects.circuitjs1.client.element.source.VarRailElm;
import com.lushprojects.circuitjs1.client.element.source.VoltageElm;
import com.lushprojects.circuitjs1.client.gui.Color;
import com.lushprojects.circuitjs1.client.gui.Font;
import com.lushprojects.circuitjs1.client.gui.Graphics;
import com.lushprojects.circuitjs1.client.gui.Gui;
import com.lushprojects.circuitjs1.client.gui.LoadFile;
import com.lushprojects.circuitjs1.client.gui.Point;
import com.lushprojects.circuitjs1.client.gui.QueryParameters;
import com.lushprojects.circuitjs1.client.gui.Rectangle;
import com.lushprojects.circuitjs1.client.gui.Scope;
import com.lushprojects.circuitjs1.client.sim.CircuitNode;
import com.lushprojects.circuitjs1.client.sim.CircuitNodeLink;
import com.lushprojects.circuitjs1.client.sim.RowInfo;
import com.lushprojects.circuitjs1.client.sim.StringTokenizer;

public class CirSim {

    Logger logger = Logger.getLogger("CirSim");
    Random random;
    public int hintType = -1;
    int hintItem1;
    int hintItem2;

    public static final int sourceRadius = 7;
    public static final double freqMult = 3.14159265 * 2 * 4;

    static final int HINT_LC = 1;
    static final int HINT_RC = 2;
    static final int HINT_3DB_C = 3;
    static final int HINT_TWINT = 4;
    static final int HINT_3DB_L = 5;
    boolean isMac;
    public LoadFile loadFileInput;
    static final double pi = 3.14159265358979323846;
    public int circuitBottom;
    // boolean analyzeFlag;
    boolean dumpMatrix;
    long myframes = 1;
    long mytime = 0;
    long myruntime = 0;
    long mydrawtime = 0;
    public double timeStep;
    public double t;
    boolean circuitNonLinear;
    int voltageSourceCount;
    int circuitMatrixSize, circuitMatrixFullSize;
    boolean circuitNeedsMap;
    double circuitMatrix[][], circuitRightSide[], origRightSide[], origMatrix[][];
    RowInfo circuitRowInfo[];
    int circuitPermute[];
    public Gui gui;
    boolean shown = false;
    public Vector<CircuitElm> elmList;
    public boolean analyzeFlag;

    public boolean converged;
    public int subIterations;

    static final int resct = 6;
    long lastTime = 0, lastFrameTime, lastIterTime, secTime = 0;
    int frames = 0;
    int steps = 0;
    int framerate = 0, steprate = 0;
    public Vector<CircuitNode> nodeList;
    CircuitElm voltageSources[];

    // Class addingClass;
    final Timer timer = new Timer() {
        public void run() {
            updateCircuit();
        }
    };
    final int FASTTIMER = 40;

    public int getrand(int x) {
        int q = random.nextInt();
        if (q < 0)
            q = -q;
        return q % x;
    }

    // Circuit applet;

    public CirSim() {
        // super("Circuit Simulator v1.6d");
        // applet = a;
        // useFrame = false;
    }

    // String baseURL = "http://www.falstad.com/circuit/";

    public void init() {

        boolean printable = false;
        boolean convention = true;
        boolean euro = false;

        random = new Random();

        gui = new Gui(this);

        CircuitElm.initClass(this);

        QueryParameters qp = new QueryParameters();

        try {
            String cct = qp.getValue("cct");

            if (cct != null)
                gui.startCircuitText = cct.replace("%24", "$");

            gui.startCircuit = qp.getValue("startCircuit");
            gui.startLabel = qp.getValue("startLabel");
            euro = qp.getBooleanValue("euroResistors", true);
            printable = qp.getBooleanValue("whiteBackground", false);
            convention = qp.getBooleanValue("conventionalCurrent", true);
        } catch (Exception e) {
        }

        String os = Navigator.getPlatform();
        isMac = (os.toLowerCase().contains("mac"));
        gui.ctrlMetaKey = (isMac) ? "Cmd" : "Ctrl";

        // main.setLayout(new CircuitLayout());
        elmList = new Vector<CircuitElm>();

        gui.generateLayout(printable, convention, euro);

        timer.scheduleRepeating(FASTTIMER);

    }

    public void updateCircuit() {
        long mystarttime;
        long myrunstarttime;
        long mydrawstarttime;
        CircuitElm realMouseElm;

        mystarttime = System.currentTimeMillis();
        if (analyzeFlag) {
            analyzeCircuit();
            analyzeFlag = false;
        }

        realMouseElm = gui.mouseElm;
        if (gui.mouseElm == null)
            gui.mouseElm = gui.stopElm;

        gui.setupScopes();

        CircuitElm.selectColor = Color.cyan;

        Graphics g = gui.beginRender();
        myrunstarttime = System.currentTimeMillis();

        if (!gui.stoppedCheck.getState()) {
            try {
                runCircuit();
            } catch (Exception e) {
                e.printStackTrace();
                analyzeFlag = true;
                // cv.repaint();
                return;
            }
            myruntime += System.currentTimeMillis() - myrunstarttime;
        }

        long sysTime = System.currentTimeMillis();

        if (!gui.stoppedCheck.getState()) {

            if (lastTime != 0) {
                int inc = (int) (sysTime - lastTime);
                double c = gui.currentBar.getValue();
                c = java.lang.Math.exp(c / 3.5 - 14.2);
                CircuitElm.currentMult = 1.7 * inc * c;
                if (!gui.conventionCheckItem.getState())
                    CircuitElm.currentMult = -CircuitElm.currentMult;
            }

            lastTime = sysTime;
        } else
            lastTime = 0;

        if (sysTime - secTime >= 1000) {
            framerate = frames;
            steprate = steps;
            frames = 0;
            steps = 0;
            secTime = sysTime;
        }
        CircuitElm.powerMult = Math.exp(gui.powerBar.getValue() / 4.762 - 7);

        int i;

        Font oldfont = CircuitElm.unitsFont;
        g.setFont(oldfont);

        mydrawstarttime = System.currentTimeMillis();

        for (i = 0; i != elmList.size(); i++) {
            if (gui.powerCheckItem.getState())
                g.setColor(Color.gray);
            /*
             * else if (conductanceCheckItem.getState())
             * g.setColor(Color.white);
             */
            getElm(i).draw(g);
        }
        mydrawtime += System.currentTimeMillis() - mydrawstarttime;

        if (gui.tempMouseMode == Gui.MODE_DRAG_ROW || gui.tempMouseMode == Gui.MODE_DRAG_COLUMN
                || gui.tempMouseMode == Gui.MODE_DRAG_POST || gui.tempMouseMode == Gui.MODE_DRAG_SELECTED)
            for (i = 0; i != elmList.size(); i++) {

                CircuitElm ce = getElm(i);
                // ce.drawPost(g, ce.x , ce.y );
                // ce.drawPost(g, ce.x2, ce.y2);
                if (ce != gui.mouseElm || gui.tempMouseMode != Gui.MODE_DRAG_POST) {
                    g.setColor(Color.gray);
                    g.fillOval(ce.x - 3, ce.y - 3, 7, 7);
                    g.fillOval(ce.x2 - 3, ce.y2 - 3, 7, 7);
                } else {
                    ce.drawHandles(g, Color.cyan);
                }
            }
        if (gui.tempMouseMode == Gui.MODE_SELECT && gui.mouseElm != null) {
            gui.mouseElm.drawHandles(g, Color.cyan);
        }
        int badnodes = 0;
        // find bad connections, nodes not connected to other elements which
        // intersect other elements' bounding boxes
        // debugged by hausen: nullPointerException
        if (nodeList != null)
            for (i = 0; i != nodeList.size(); i++) {
                CircuitNode cn = getCircuitNode(i);
                if (!cn.internal && cn.links.size() == 1) {
                    int bb = 0, j;
                    CircuitNodeLink cnl = cn.links.elementAt(0);
                    for (j = 0; j != elmList.size(); j++) { // TODO: (hausen)
                        // see if this
                        // change does not
                        // break stuff
                        CircuitElm ce = getElm(j);
                        if (ce instanceof GraphicElm)
                            continue;
                        if (cnl.elm != ce && getElm(j).boundingBox.contains(cn.x, cn.y))
                            bb++;
                    }
                    if (bb > 0) {
                        g.setColor(Color.red);
                        g.fillOval(cn.x - 3, cn.y - 3, 7, 7);
                        badnodes++;
                    }
                }
            }

        gui.render(g, oldfont, badnodes, t);

        gui.mouseElm = realMouseElm;

        frames++;

        lastFrameTime = lastTime;
        mytime = mytime + System.currentTimeMillis() - mystarttime;
        myframes++;
    }

    public void drawElmWithHandles(CircuitElm elm, Graphics g) {
        elm.draw(g);
        elm.drawHandles(g, Color.cyan);

    }

    public String[] getInfo() {

        String info[] = new String[10];
        if (gui.mouseElm != null) {

            if (gui.mousePost == -1)
                gui.mouseElm.getInfo(info);
            else
                info[0] = "V = " + CircuitElm.getUnitText(gui.mouseElm.getPostVoltage(gui.mousePost), "V");
            /*
             * //shownodes for (i = 0; i != mouseElm.getPostCount(); i++)
             * info[0] += " " + mouseElm.nodes[i]; if
             * (mouseElm.getVoltageSourceCount() > 0) info[0] += ";" +
             * (mouseElm.getVoltageSource()+nodeList.size());
             */

        } else {
            // IES Eliminate hack of showFormat
            // CircuitElm.showFormat.setMinimumFractionDigits(2);
            info[0] = "t = " + CircuitElm.getUnitText(t, "s");
            // CircuitElm.showFormat.setMinimumFractionDigits(0);
        }
        return info;
    }

    public String getHint() {
        CircuitElm c1 = getElm(hintItem1);
        CircuitElm c2 = getElm(hintItem2);
        if (c1 == null || c2 == null)
            return null;
        if (hintType == HINT_LC) {
            if (!(c1 instanceof InductorElm))
                return null;
            if (!(c2 instanceof CapacitorElm /* || c2 instanceof Capacitor2Elm */))
                return null;
            InductorElm ie = (InductorElm) c1;
            CapacitorElm ce = (CapacitorElm) c2;
            return "res.f = "
                    + CircuitElm.getUnitText(1 / (2 * pi * Math.sqrt(ie.inductance * ce.capacitance)), "Hz");
        }
        if (hintType == HINT_RC) {
            if (!(c1 instanceof ResistorElm))
                return null;
            if (!(c2 instanceof CapacitorElm))
                return null;
            ResistorElm re = (ResistorElm) c1;
            CapacitorElm ce = (CapacitorElm) c2;
            return "RC = " + CircuitElm.getUnitText(re.resistance * ce.capacitance, "s");
        }
        if (hintType == HINT_3DB_C) {
            if (!(c1 instanceof ResistorElm))
                return null;
            if (!(c2 instanceof CapacitorElm))
                return null;
            ResistorElm re = (ResistorElm) c1;
            CapacitorElm ce = (CapacitorElm) c2;
            return "f.3db = " + CircuitElm.getUnitText(1 / (2 * pi * re.resistance * ce.capacitance), "Hz");
        }
        if (hintType == HINT_3DB_L) {
            if (!(c1 instanceof ResistorElm))
                return null;
            if (!(c2 instanceof InductorElm))
                return null;
            ResistorElm re = (ResistorElm) c1;
            InductorElm ie = (InductorElm) c2;
            return "f.3db = " + CircuitElm.getUnitText(re.resistance / (2 * pi * ie.inductance), "Hz");
        }
        if (hintType == HINT_TWINT) {
            if (!(c1 instanceof ResistorElm))
                return null;
            if (!(c2 instanceof CapacitorElm))
                return null;
            ResistorElm re = (ResistorElm) c1;
            CapacitorElm ce = (CapacitorElm) c2;
            return "fc = " + CircuitElm.getUnitText(1 / (2 * pi * re.resistance * ce.capacitance), "Hz");
        }
        return null;
    }

    // public void toggleSwitch(int n) {
    // int i;
    // for (i = 0; i != elmList.size(); i++) {
    // CircuitElm ce = getElm(i);
    // if (ce instanceof SwitchElm) {
    // n--;
    // if (n == 0) {
    // ((SwitchElm) ce).toggle();
    // analyzeFlag = true;
    // cv.repaint();
    // return;
    // }
    // }
    // }
    // }

    public void needAnalyze() {
        analyzeFlag = true;
        // cv.repaint();
    }

    public CircuitNode getCircuitNode(int n) {
        if (n >= nodeList.size())
            return null;
        return nodeList.elementAt(n);
    }

    public CircuitElm getElm(int n) {
        if (n >= elmList.size())
            return null;
        return elmList.elementAt(n);
    }

    void analyzeCircuit() {
        calcCircuitBottom();
        if (elmList.isEmpty())
            return;
        gui.stopMessage = null;
        gui.stopElm = null;
        int i, j;
        int vscount = 0;
        nodeList = new Vector<CircuitNode>();
        boolean gotGround = false;
        boolean gotRail = false;
        CircuitElm volt = null;

        // System.out.println("ac1");
        // look for voltage or ground element
        for (i = 0; i != elmList.size(); i++) {
            CircuitElm ce = getElm(i);
            if (ce instanceof GroundElm) {
                gotGround = true;
                break;
            }
            if (ce instanceof RailElm)
                gotRail = true;
            if (volt == null && ce instanceof VoltageElm)
                volt = ce;
        }

        // if no ground, and no rails, then the voltage elm's first terminal
        // is ground
        if (!gotGround && volt != null && !gotRail) {
            CircuitNode cn = new CircuitNode();
            Point pt = volt.getPost(0);
            cn.x = (int) pt.x;
            cn.y = (int) pt.y;
            nodeList.addElement(cn);
        } else {
            // otherwise allocate extra node for ground
            CircuitNode cn = new CircuitNode();
            cn.x = cn.y = -1;
            nodeList.addElement(cn);
        }
        // System.out.println("ac2");

        // allocate nodes and voltage sources
        for (i = 0; i != elmList.size(); i++) {
            CircuitElm ce = getElm(i);
            int inodes = ce.getInternalNodeCount();
            int ivs = ce.getVoltageSourceCount();
            int posts = ce.getPostCount();

            // allocate a node for each post and match posts to nodes
            for (j = 0; j != posts; j++) {
                Point pt = ce.getPost(j);
                int k;
                for (k = 0; k != nodeList.size(); k++) {
                    CircuitNode cn = getCircuitNode(k);
                    if (pt.x == cn.x && pt.y == cn.y)
                        break;
                }
                if (k == nodeList.size()) {
                    CircuitNode cn = new CircuitNode();
                    cn.x = (int) pt.x;
                    cn.y = (int) pt.y;
                    CircuitNodeLink cnl = new CircuitNodeLink();
                    cnl.num = j;
                    cnl.elm = ce;
                    cn.links.addElement(cnl);
                    ce.setNode(j, nodeList.size());
                    nodeList.addElement(cn);
                } else {
                    CircuitNodeLink cnl = new CircuitNodeLink();
                    cnl.num = j;
                    cnl.elm = ce;
                    getCircuitNode(k).links.addElement(cnl);
                    ce.setNode(j, k);
                    // if it's the ground node, make sure the node voltage is 0,
                    // cause it may not get set later
                    if (k == 0)
                        ce.setNodeVoltage(j, 0);
                }
            }
            for (j = 0; j != inodes; j++) {
                CircuitNode cn = new CircuitNode();
                cn.x = cn.y = -1;
                cn.internal = true;
                CircuitNodeLink cnl = new CircuitNodeLink();
                cnl.num = j + posts;
                cnl.elm = ce;
                cn.links.addElement(cnl);
                ce.setNode(cnl.num, nodeList.size());
                nodeList.addElement(cn);
            }
            vscount += ivs;
        }
        voltageSources = new CircuitElm[vscount];
        vscount = 0;
        circuitNonLinear = false;
        // System.out.println("ac3");

        // determine if circuit is nonlinear
        for (i = 0; i != elmList.size(); i++) {
            CircuitElm ce = getElm(i);
            if (ce.nonLinear())
                circuitNonLinear = true;
            int ivs = ce.getVoltageSourceCount();
            for (j = 0; j != ivs; j++) {
                voltageSources[vscount] = ce;
                ce.setVoltageSource(j, vscount++);
            }
        }
        voltageSourceCount = vscount;

        int matrixSize = nodeList.size() - 1 + vscount;
        circuitMatrix = new double[matrixSize][matrixSize];
        circuitRightSide = new double[matrixSize];
        origMatrix = new double[matrixSize][matrixSize];
        origRightSide = new double[matrixSize];
        circuitMatrixSize = circuitMatrixFullSize = matrixSize;
        circuitRowInfo = new RowInfo[matrixSize];
        circuitPermute = new int[matrixSize];
        int vs = 0;
        for (i = 0; i != matrixSize; i++)
            circuitRowInfo[i] = new RowInfo();
        circuitNeedsMap = false;

        // stamp linear circuit elements
        for (i = 0; i != elmList.size(); i++) {
            CircuitElm ce = getElm(i);
            ce.stamp();
        }
        // System.out.println("ac4");

        // determine nodes that are unconnected
        boolean closure[] = new boolean[nodeList.size()];
        boolean tempclosure[] = new boolean[nodeList.size()];
        boolean changed = true;
        closure[0] = true;
        while (changed) {
            changed = false;
            for (i = 0; i != elmList.size(); i++) {
                CircuitElm ce = getElm(i);
                // loop through all ce's nodes to see if they are connected
                // to other nodes not in closure
                for (j = 0; j < ce.getPostCount(); j++) {
                    if (!closure[ce.getNode(j)]) {
                        if (ce.hasGroundConnection(j))
                            closure[ce.getNode(j)] = changed = true;
                        continue;
                    }
                    int k;
                    for (k = 0; k != ce.getPostCount(); k++) {
                        if (j == k)
                            continue;
                        int kn = ce.getNode(k);
                        if (ce.getConnection(j, k) && !closure[kn]) {
                            closure[kn] = true;
                            changed = true;
                        }
                    }
                }
            }
            if (changed)
                continue;

            // connect unconnected nodes
            for (i = 0; i != nodeList.size(); i++)
                if (!closure[i] && !getCircuitNode(i).internal) {
                    System.out.println("node " + i + " unconnected");
                    stampResistor(0, i, 1e8);
                    closure[i] = true;
                    changed = true;
                    break;
                }
        }
        // System.out.println("ac5");

        for (i = 0; i != elmList.size(); i++) {
            CircuitElm ce = getElm(i);
            // look for inductors with no current path
            if (ce instanceof InductorElm) {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1));
                // first try findPath with maximum depth of 5, to avoid
                // slowdowns
                if (!fpi.findPath(ce.getNode(0), 5) && !fpi.findPath(ce.getNode(0))) {
                    System.out.println(ce + " no path");
                    ce.reset();
                }
            }
            // look for current sources with no current path
            if (ce instanceof CurrentElm) {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.INDUCT, ce, ce.getNode(1));
                if (!fpi.findPath(ce.getNode(0))) {
                    stop("No path for current source!", ce);
                    return;
                }
            }
            // look for voltage source loops
            // IES
            if ((ce instanceof VoltageElm && ce.getPostCount() == 2) || ce instanceof WireElm) {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, ce.getNode(1));
                if (fpi.findPath(ce.getNode(0))) {
                    stop("Voltage source/wire loop with no resistance!", ce);
                    return;
                }
            }
            // look for shorted caps, or caps w/ voltage but no R
            if (ce instanceof CapacitorElm || ce instanceof Capacitor2Elm) {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.SHORT, ce, ce.getNode(1));
                if (fpi.findPath(ce.getNode(0))) {
                    System.out.println(ce + " shorted");
                    ce.reset();
                } else {
                    fpi = new FindPathInfo(FindPathInfo.CAP_V, ce, ce.getNode(1));
                    if (fpi.findPath(ce.getNode(0))) {
                        stop("Capacitor loop with no resistance!", ce);
                        return;
                    }
                }
            }
        }
        // System.out.println("ac6");

        // simplify the matrix; this speeds things up quite a bit
        for (i = 0; i != matrixSize; i++) {
            int qm = -1, qp = -1;
            double qv = 0;
            RowInfo re = circuitRowInfo[i];
            /*
             * System.out.println("row " + i + " " + re.lsChanges + " " +
             * re.rsChanges + " " + re.dropRow);
             */
            if (re.lsChanges || re.dropRow || re.rsChanges)
                continue;
            double rsadd = 0;

            // look for rows that can be removed
            for (j = 0; j != matrixSize; j++) {
                double q = circuitMatrix[i][j];
                GWT.log("i=" + i + " j=" + j + " q=" + q);
                if (circuitRowInfo[j].type == RowInfo.ROW_CONST) {
                    // keep a running total of const values that have been
                    // removed already
                    rsadd -= circuitRowInfo[j].value * q;
                    continue;
                }
                if (q == 0)
                    continue;
                if (qp == -1) {
                    qp = j;
                    qv = q;
                    continue;
                }
                if (qm == -1 && q == -qv) {
                    qm = j;
                    continue;
                }
                break;
            }
            // System.out.println("line " + i + " " + qp + " " + qm + " " + j);
            /*
             * if (qp != -1 && circuitRowInfo[qp].lsChanges) {
             * System.out.println("lschanges"); continue; } if (qm != -1 &&
             * circuitRowInfo[qm].lsChanges) { System.out.println("lschanges");
             * continue; }
             */
            if (j == matrixSize) {
                if (qp == -1) {
                    stop("Matrix error: " + matrixSize, null);
                    logger.warning("Matrix Error");
                    GWT.log("Matrix Error");
                    return;
                }
                RowInfo elt = circuitRowInfo[qp];
                if (qm == -1) {
                    // we found a row with only one nonzero entry; that value
                    // is a constant
                    int k;
                    for (k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++) {
                        // follow the chain
                        /*
                         * System.out.println("following equal chain from " + i
                         * + " " + qp + " to " + elt.nodeEq);
                         */
                        qp = elt.nodeEq;
                        elt = circuitRowInfo[qp];
                    }
                    if (elt.type == RowInfo.ROW_EQUAL) {
                        // break equal chains
                        // System.out.println("Break equal chain");
                        elt.type = RowInfo.ROW_NORMAL;
                        continue;
                    }
                    if (elt.type != RowInfo.ROW_NORMAL) {
                        System.out.println("type already " + elt.type + " for " + qp + "!");
                        continue;
                    }
                    elt.type = RowInfo.ROW_CONST;
                    elt.value = (circuitRightSide[i] + rsadd) / qv;
                    circuitRowInfo[i].dropRow = true;
                    // System.out.println(qp + " * " + qv + " = const " +
                    // elt.value);
                    i = -1; // start over from scratch
                } else if (circuitRightSide[i] + rsadd == 0) {
                    // we found a row with only two nonzero entries, and one
                    // is the negative of the other; the values are equal
                    if (elt.type != RowInfo.ROW_NORMAL) {
                        // System.out.println("swapping");
                        int qq = qm;
                        qm = qp;
                        qp = qq;
                        elt = circuitRowInfo[qp];
                        if (elt.type != RowInfo.ROW_NORMAL) {
                            // we should follow the chain here, but this
                            // hardly ever happens so it's not worth worrying
                            // about
                            System.out.println("swap failed");
                            continue;
                        }
                    }
                    elt.type = RowInfo.ROW_EQUAL;
                    elt.nodeEq = qm;
                    circuitRowInfo[i].dropRow = true;
                    // System.out.println(qp + " = " + qm);
                }
            }
        }
        // System.out.println("ac7");

        // find size of new matrix
        int nn = 0;
        for (i = 0; i != matrixSize; i++) {
            RowInfo elt = circuitRowInfo[i];
            if (elt.type == RowInfo.ROW_NORMAL) {
                elt.mapCol = nn++;
                // System.out.println("col " + i + " maps to " + elt.mapCol);
                continue;
            }
            if (elt.type == RowInfo.ROW_EQUAL) {
                RowInfo e2 = null;
                // resolve chains of equality; 100 max steps to avoid loops
                for (j = 0; j != 100; j++) {
                    e2 = circuitRowInfo[elt.nodeEq];
                    if (e2.type != RowInfo.ROW_EQUAL)
                        break;
                    if (i == e2.nodeEq)
                        break;
                    elt.nodeEq = e2.nodeEq;
                }
            }
            if (elt.type == RowInfo.ROW_CONST)
                elt.mapCol = -1;
        }
        for (i = 0; i != matrixSize; i++) {
            RowInfo elt = circuitRowInfo[i];
            if (elt.type == RowInfo.ROW_EQUAL) {
                RowInfo e2 = circuitRowInfo[elt.nodeEq];
                if (e2.type == RowInfo.ROW_CONST) {
                    // if something is equal to a const, it's a const
                    elt.type = e2.type;
                    elt.value = e2.value;
                    elt.mapCol = -1;
                    // System.out.println(i + " = [late]const " + elt.value);
                } else {
                    elt.mapCol = e2.mapCol;
                    // System.out.println(i + " maps to: " + e2.mapCol);
                }
            }
        }
        // System.out.println("ac8");

        /*
         * System.out.println("matrixSize = " + matrixSize);
         * 
         * for (j = 0; j != circuitMatrixSize; j++) { System.out.println(j +
         * ": "); for (i = 0; i != circuitMatrixSize; i++)
         * System.out.print(circuitMatrix[j][i] + " "); System.out.print("  " +
         * circuitRightSide[j] + "\n"); } System.out.print("\n");
         */

        // make the new, simplified matrix
        int newsize = nn;
        double newmatx[][] = new double[newsize][newsize];
        double newrs[] = new double[newsize];
        int ii = 0;
        for (i = 0; i != matrixSize; i++) {
            RowInfo rri = circuitRowInfo[i];
            if (rri.dropRow) {
                rri.mapRow = -1;
                continue;
            }
            newrs[ii] = circuitRightSide[i];
            rri.mapRow = ii;
            // System.out.println("Row " + i + " maps to " + ii);
            for (j = 0; j != matrixSize; j++) {
                RowInfo ri = circuitRowInfo[j];
                if (ri.type == RowInfo.ROW_CONST)
                    newrs[ii] -= ri.value * circuitMatrix[i][j];
                else
                    newmatx[ii][ri.mapCol] += circuitMatrix[i][j];
            }
            ii++;
        }

        circuitMatrix = newmatx;
        circuitRightSide = newrs;
        matrixSize = circuitMatrixSize = newsize;
        for (i = 0; i != matrixSize; i++)
            origRightSide[i] = circuitRightSide[i];
        for (i = 0; i != matrixSize; i++)
            for (j = 0; j != matrixSize; j++)
                origMatrix[i][j] = circuitMatrix[i][j];
        circuitNeedsMap = true;

        /*
         * System.out.println("matrixSize = " + matrixSize + " " +
         * circuitNonLinear); for (j = 0; j != circuitMatrixSize; j++) { for (i
         * = 0; i != circuitMatrixSize; i++)
         * System.out.print(circuitMatrix[j][i] + " "); System.out.print("  " +
         * circuitRightSide[j] + "\n"); } System.out.print("\n");
         */

        // if a matrix is linear, we can do the lu_factor here instead of
        // needing to do it every frame
        if (!circuitNonLinear) {
            if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute)) {
                stop("Singular matrix!", null);
                return;
            }
        }
    }

    public void calcCircuitBottom() {
        int i;
        circuitBottom = 0;
        for (i = 0; i != elmList.size(); i++) {
            Rectangle rect = getElm(i).boundingBox;
            int bottom = rect.getHeight() + rect.getY();
            if (bottom > circuitBottom)
                circuitBottom = bottom;
        }
    }

    class FindPathInfo {
        static final int INDUCT = 1;
        static final int VOLTAGE = 2;
        static final int SHORT = 3;
        static final int CAP_V = 4;
        boolean used[];
        int dest;
        CircuitElm firstElm;
        int type;

        FindPathInfo(int t, CircuitElm e, int d) {
            dest = d;
            type = t;
            firstElm = e;
            used = new boolean[nodeList.size()];
        }

        boolean findPath(int n1) {
            return findPath(n1, -1);
        }

        boolean findPath(int n1, int depth) {
            if (n1 == dest)
                return true;
            if (depth-- == 0)
                return false;
            if (used[n1]) {
                // System.out.println("used " + n1);
                return false;
            }
            used[n1] = true;
            int i;
            for (i = 0; i != elmList.size(); i++) {
                CircuitElm ce = getElm(i);
                if (ce == firstElm)
                    continue;
                if (type == INDUCT) {
                    if (ce instanceof CurrentElm)
                        continue;
                }
                if (type == VOLTAGE) {
                    if (!(ce.isWire() || ce instanceof VoltageElm))
                        continue;
                }
                if (type == SHORT && !ce.isWire())
                    continue;
                if (type == CAP_V) {
                    if (!(ce.isWire() || ce instanceof CapacitorElm || ce instanceof Capacitor2Elm
                            || ce instanceof VoltageElm))
                        continue;
                }
                if (n1 == 0) {
                    // look for posts which have a ground connection;
                    // our path can go through ground
                    int j;
                    for (j = 0; j != ce.getPostCount(); j++)
                        if (ce.hasGroundConnection(j) && findPath(ce.getNode(j), depth)) {
                            used[n1] = false;
                            return true;
                        }
                }
                int j;
                for (j = 0; j != ce.getPostCount(); j++) {
                    // System.out.println(ce + " " + ce.getNode(j));
                    if (ce.getNode(j) == n1)
                        break;
                }
                if (j == ce.getPostCount())
                    continue;
                if (ce.hasGroundConnection(j) && findPath(0, depth)) {
                    // System.out.println(ce + " has ground");
                    used[n1] = false;
                    return true;
                }
                if (type == INDUCT && ce instanceof InductorElm) {
                    double c = ce.getCurrent();
                    if (j == 0)
                        c = -c;
                    // System.out.println("matching " + c + " to " +
                    // firstElm.getCurrent());
                    // System.out.println(ce + " " + firstElm);
                    if (Math.abs(c - firstElm.getCurrent()) > 1e-10)
                        continue;
                }
                int k;
                for (k = 0; k != ce.getPostCount(); k++) {
                    if (j == k)
                        continue;
                    // System.out.println(ce + " " + ce.getNode(j) + "-" +
                    // ce.getNode(k));
                    if (ce.getConnection(j, k) && findPath(ce.getNode(k), depth)) {
                        // System.out.println("got findpath " + n1);
                        used[n1] = false;
                        return true;
                    }
                    // System.out.println("back on findpath " + n1);
                }
            }
            used[n1] = false;
            // System.out.println(n1 + " failed");
            return false;
        }
    }

    public void stop(String s, CircuitElm ce) {
        circuitMatrix = null;
        analyzeFlag = false;
        gui.stop(s, ce);
    }

    // control voltage source vs with voltage from n1 to n2 (must
    // also call stampVoltageSource())
    public void stampVCVS(int n1, int n2, double coef, int vs) {
        int vn = nodeList.size() + vs;
        stampMatrix(vn, n1, coef);
        stampMatrix(vn, n2, -coef);
    }

    // stamp independent voltage source #vs, from n1 to n2, amount v
    public void stampVoltageSource(int n1, int n2, int vs, double v) {
        int vn = nodeList.size() + vs;
        stampMatrix(vn, n1, -1);
        stampMatrix(vn, n2, 1);
        stampRightSide(vn, v);
        stampMatrix(n1, vn, 1);
        stampMatrix(n2, vn, -1);
    }

    // use this if the amount of voltage is going to be updated in doStep()
    public void stampVoltageSource(int n1, int n2, int vs) {
        int vn = nodeList.size() + vs;
        stampMatrix(vn, n1, -1);
        stampMatrix(vn, n2, 1);
        stampRightSide(vn);
        stampMatrix(n1, vn, 1);
        stampMatrix(n2, vn, -1);
    }

    public void updateVoltageSource(int n1, int n2, int vs, double v) {
        int vn = nodeList.size() + vs;
        stampRightSide(vn, v);
    }

    public void stampResistor(int n1, int n2, double r) {
        double r0 = 1 / r;
        if (Double.isNaN(r0) || Double.isInfinite(r0)) {
            System.out.print("bad resistance " + r + " " + r0 + "\n");
            int a = 0;
            a /= a;
        }
        stampMatrix(n1, n1, r0);
        stampMatrix(n2, n2, r0);
        stampMatrix(n1, n2, -r0);
        stampMatrix(n2, n1, -r0);
    }

    public void stampConductance(int n1, int n2, double r0) {
        stampMatrix(n1, n1, r0);
        stampMatrix(n2, n2, r0);
        stampMatrix(n1, n2, -r0);
        stampMatrix(n2, n1, -r0);
    }

    // current from cn1 to cn2 is equal to voltage from vn1 to 2, divided by g
    public void stampVCCurrentSource(int cn1, int cn2, int vn1, int vn2, double g) {
        stampMatrix(cn1, vn1, g);
        stampMatrix(cn2, vn2, g);
        stampMatrix(cn1, vn2, -g);
        stampMatrix(cn2, vn1, -g);
    }

    public void stampCurrentSource(int n1, int n2, double i) {
        stampRightSide(n1, -i);
        stampRightSide(n2, i);
    }

    // stamp a current source from n1 to n2 depending on current through vs
    public void stampCCCS(int n1, int n2, int vs, double gain) {
        int vn = nodeList.size() + vs;
        stampMatrix(n1, vn, gain);
        stampMatrix(n2, vn, -gain);
    }

    // stamp value x in row i, column j, meaning that a voltage change
    // of dv in node j will increase the current into node i by x dv.
    // (Unless i or j is a voltage source node.)
    public void stampMatrix(int i, int j, double x) {
        if (i > 0 && j > 0) {
            if (circuitNeedsMap) {
                i = circuitRowInfo[i - 1].mapRow;
                RowInfo ri = circuitRowInfo[j - 1];
                if (ri.type == RowInfo.ROW_CONST) {
                    // System.out.println("Stamping constant " + i + " " + j +
                    // " " + x);
                    circuitRightSide[i] -= x * ri.value;
                    return;
                }
                j = ri.mapCol;
                // System.out.println("stamping " + i + " " + j + " " + x);
            } else {
                i--;
                j--;
            }
            circuitMatrix[i][j] += x;
        }
    }

    // stamp value x on the right side of row i, representing an
    // independent current source flowing into node i
    public void stampRightSide(int i, double x) {
        if (i > 0) {
            if (circuitNeedsMap) {
                i = circuitRowInfo[i - 1].mapRow;
                // System.out.println("stamping " + i + " " + x);
            } else
                i--;
            circuitRightSide[i] += x;
        }
    }

    // indicate that the value on the right side of row i changes in doStep()
    public void stampRightSide(int i) {
        // System.out.println("rschanges true " + (i-1));
        if (i > 0)
            circuitRowInfo[i - 1].rsChanges = true;
    }

    // indicate that the values on the left side of row i change in doStep()
    public void stampNonLinear(int i) {
        if (i > 0)
            circuitRowInfo[i - 1].lsChanges = true;
    }

    void runCircuit() {
        if (circuitMatrix == null || elmList.size() == 0) {
            circuitMatrix = null;
            return;
        }
        int iter;
        // int maxIter = getIterCount();
        boolean debugprint = dumpMatrix;
        dumpMatrix = false;
        long steprate = (long) (160 * gui.getIterCount());
        long tm = System.currentTimeMillis();
        long lit = lastIterTime;
        if (1000 >= steprate * (tm - lastIterTime))
            return;

        for (iter = 1;; iter++) {
            int i, j, k, subiter;
            for (i = 0; i != elmList.size(); i++) {
                CircuitElm ce = getElm(i);
                ce.startIteration();
            }
            steps++;
            final int subiterCount = 5000;
            for (subiter = 0; subiter != subiterCount; subiter++) {
                converged = true;
                subIterations = subiter;
                for (i = 0; i != circuitMatrixSize; i++)
                    circuitRightSide[i] = origRightSide[i];
                if (circuitNonLinear) {
                    for (i = 0; i != circuitMatrixSize; i++)
                        for (j = 0; j != circuitMatrixSize; j++)
                            circuitMatrix[i][j] = origMatrix[i][j];
                }
                for (i = 0; i != elmList.size(); i++) {
                    CircuitElm ce = getElm(i);
                    ce.doStep();
                }
                if (gui.stopMessage != null)
                    return;
                boolean printit = debugprint;
                debugprint = false;
                for (j = 0; j != circuitMatrixSize; j++) {
                    for (i = 0; i != circuitMatrixSize; i++) {
                        double x = circuitMatrix[i][j];
                        if (Double.isNaN(x) || Double.isInfinite(x)) {
                            stop("nan/infinite matrix!", null);
                            return;
                        }
                    }
                }
                if (printit) {
                    for (j = 0; j != circuitMatrixSize; j++) {
                        for (i = 0; i != circuitMatrixSize; i++)
                            System.out.print(circuitMatrix[j][i] + ",");
                        System.out.print("  " + circuitRightSide[j] + "\n");
                    }
                    System.out.print("\n");
                }
                if (circuitNonLinear) {
                    if (converged && subiter > 0)
                        break;
                    if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute)) {
                        stop("Singular matrix!", null);
                        return;
                    }
                }
                lu_solve(circuitMatrix, circuitMatrixSize, circuitPermute, circuitRightSide);

                for (j = 0; j != circuitMatrixFullSize; j++) {
                    RowInfo ri = circuitRowInfo[j];
                    double res = 0;
                    if (ri.type == RowInfo.ROW_CONST)
                        res = ri.value;
                    else
                        res = circuitRightSide[ri.mapCol];
                    /*
                     * System.out.println(j + " " + res + " " + ri.type + " " +
                     * ri.mapCol);
                     */
                    if (Double.isNaN(res)) {
                        converged = false;
                        // debugprint = true;
                        break;
                    }
                    if (j < nodeList.size() - 1) {
                        CircuitNode cn = getCircuitNode(j + 1);
                        for (k = 0; k != cn.links.size(); k++) {
                            CircuitNodeLink cnl = (CircuitNodeLink) cn.links.elementAt(k);
                            cnl.elm.setNodeVoltage(cnl.num, res);
                        }
                    } else {
                        int ji = j - (nodeList.size() - 1);
                        // System.out.println("setting vsrc " + ji + " to " +
                        // res);
                        voltageSources[ji].setCurrent(ji, res);
                    }
                }
                if (!circuitNonLinear)
                    break;

            } // end for (subiter = 0; subiter != subiterCount; subiter++)

            if (subiter > 5)
                System.out.print("converged after " + subiter + " iterations\n");
            if (subiter == subiterCount) {
                stop("Convergence failed!", null);
                break;
            }
            t += timeStep;
            for (i = 0; i != gui.scopeCount; i++)
                gui.scopes[i].timeStep();
            tm = System.currentTimeMillis();
            lit = tm;
            if (iter * 1000 >= steprate * (tm - lastIterTime) || (tm - lastFrameTime > 500))
                break;
        } // for (iter = 1; ; iter++)
        lastIterTime = lit;
        // System.out.println((System.currentTimeMillis()-lastFrameTime)/(double)
        // iter);
    }

    int min(int a, int b) {
        return (a < b) ? a : b;
    }

    int max(int a, int b) {
        return (a > b) ? a : b;
    }

    void editFuncPoint(int x, int y) {
        // XXX
        // cv.repaint(pause);
    }

    // public void componentHidden(ComponentEvent e){}
    // public void componentMoved(ComponentEvent e){}
    // public void componentShown(ComponentEvent e) {
    // //cv.repaint();
    // }

    // public void componentResized(ComponentEvent e) {
    // // handleResize();
    // //cv.repaint(100);
    // }

    public void resetAction() {
        int i;
        for (i = 0; i != elmList.size(); i++)
            getElm(i).reset();
        for (i = 0; i != gui.scopeCount; i++)
            gui.scopes[i].resetGraph();
        // TODO: Will need to do IE bug fix here?
        analyzeFlag = true;
        t = 0;
        gui.stoppedCheck.setState(false);
    }

    public String dumpCircuit() {
        int i;
        int f = (gui.dotsCheckItem.getState()) ? 1 : 0;
        f |= (gui.smallGridCheckItem.getState()) ? 2 : 0;
        f |= (gui.voltsCheckItem.getState()) ? 0 : 4;
        f |= (gui.powerCheckItem.getState()) ? 8 : 0;
        f |= (gui.showValuesCheckItem.getState()) ? 0 : 16;
        // 32 = linear scale in afilter
        String dump = "$ " + f + " " + timeStep + " " + gui.getIterCount() + " " + gui.currentBar.getValue() + " "
                + CircuitElm.voltageRange + " " + gui.powerBar.getValue() + "\n";

        for (i = 0; i != elmList.size(); i++)
            dump += getElm(i).dump() + "\n";
        for (i = 0; i != gui.scopeCount; i++) {
            String d = gui.scopes[i].dump();
            if (d != null)
                dump += d + "\n";
        }
        if (hintType != -1)
            dump += "h " + hintType + " " + hintItem1 + " " + hintItem2 + "\n";
        return dump;
    }

    public void getSetupList(final boolean openDefault) {

        String url;
        url = GWT.getModuleBaseURL() + "setuplist.txt" + "?v=" + random.nextInt();
        RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url);
        try {
            requestBuilder.sendRequest(null, new RequestCallback() {
                public void onError(Request request, Throwable exception) {
                    GWT.log("File Error Response", exception);
                }

                public void onResponseReceived(Request request, Response response) {
                    // processing goes here
                    if (response.getStatusCode() == Response.SC_OK) {
                        String text = response.getText();
                        gui.processSetupList(text.getBytes(), text.length(), openDefault);
                        // end or processing
                    } else
                        GWT.log("Bad file server response:" + response.getStatusText());
                }
            });
        } catch (RequestException e) {
            GWT.log("failed file reading", e);
        }
    }

    public void readSetup(String text, boolean centre) {
        readSetup(text, false, centre);
    }

    public void readSetup(String text, boolean retain, boolean centre) {
        readSetup(text.getBytes(), text.length(), retain, centre);
        // IES - remove interaction
        // titleLabel.setText("untitled");
    }

    public void readSetupFile(String str, String title, boolean centre) {
        t = 0;
        System.out.println(str);
        // try {
        // TODO: Maybe think about some better approach to cache management!
        String url = GWT.getModuleBaseURL() + "circuits/" + str + "?v=" + random.nextInt();
        loadFileFromURL(url, centre);
        // URL url = new URL(getCodeBase() + "circuits/" + str);
        // ByteArrayOutputStream ba = readUrlData(url);
        // readSetup(ba.toByteArray(), ba.size(), false);
        // } catch (Exception e1) {
        // try {
        // URL url = getClass().getClassLoader().getResource(
        // "circuits/" + str);
        // ByteArrayOutputStream ba = readUrlData(url);
        // readSetup(ba.toByteArray(), ba.size(), false);
        // } catch (Exception e) {
        // e.printStackTrace();
        // stop("Unable to read " + str + "!", null);
        // }
        // }
        // IES - remove interaction
        // titleLabel.setText(title);
    }

    void loadFileFromURL(String url, final boolean centre) {
        RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, url);
        try {
            requestBuilder.sendRequest(null, new RequestCallback() {
                public void onError(Request request, Throwable exception) {
                    GWT.log("File Error Response", exception);
                }

                public void onResponseReceived(Request request, Response response) {
                    if (response.getStatusCode() == Response.SC_OK) {
                        String text = response.getText();
                        readSetup(text.getBytes(), text.length(), false, centre);
                    } else
                        GWT.log("Bad file server response:" + response.getStatusText());
                }
            });
        } catch (RequestException e) {
            GWT.log("failed file reading", e);
        }

    }

    public void readSetup(byte b[], int len, boolean retain, boolean centre) {
        int i;
        if (!retain) {
            for (i = 0; i != elmList.size(); i++) {
                CircuitElm ce = getElm(i);
                ce.delete();
            }
            elmList.removeAllElements();
            hintType = -1;
            timeStep = 5e-6;
            CircuitElm.voltageRange = 5;

            gui.dotsCheckItem.setState(false);
            gui.smallGridCheckItem.setState(false);
            gui.powerCheckItem.setState(false);
            gui.voltsCheckItem.setState(true);
            gui.showValuesCheckItem.setState(true);
            gui.setGrid();
            gui.speedBar.setValue(117); // 57
            gui.currentBar.setValue(50);
            gui.powerBar.setValue(50);
            gui.scopeCount = 0;

        }
        // cv.repaint();
        int p;
        for (p = 0; p < len;) {
            int l;
            int linelen = len - p; // IES - changed to allow the last line to
            // not end with a delim.
            for (l = 0; l != len - p; l++)
                if (b[l + p] == '\n' || b[l + p] == '\r') {
                    linelen = l++;
                    if (l + p < b.length && b[l + p] == '\n')
                        l++;
                    break;
                }
            String line = new String(b, p, linelen);
            StringTokenizer st = new StringTokenizer(line, " +\t\n\r\f");
            while (st.hasMoreTokens()) {
                String type = st.nextToken();
                int tint = type.charAt(0);
                try {
                    if (tint == 'o') {
                        Scope sc = new Scope(this);
                        sc.position = gui.scopeCount;
                        sc.undump(st);
                        gui.scopes[gui.scopeCount++] = sc;
                        break;
                    }
                    if (tint == 'h') {
                        readHint(st);
                        break;
                    }
                    if (tint == '$') {
                        readOptions(st);
                        break;
                    }
                    if (tint == '%' || tint == '?' || tint == 'B') {
                        // ignore afilter-specific stuff
                        break;
                    }
                    if (tint >= '0' && tint <= '9')
                        tint = new Integer(type).intValue();
                    int x1 = new Integer(st.nextToken()).intValue();
                    int y1 = new Integer(st.nextToken()).intValue();
                    int x2 = new Integer(st.nextToken()).intValue();
                    int y2 = new Integer(st.nextToken()).intValue();
                    int f = new Integer(st.nextToken()).intValue();
                    // The following lines are functionally replaced by the call
                    // to
                    // createCe below
                    // Class cls = dumpTypes[tint];
                    // if (cls == null) {
                    // System.out.println("unrecognized dump type: " + type);
                    // break;
                    // }
                    // // find element class
                    // Class carr[] = new Class[6];
                    // //carr[0] = getClass();
                    // carr[0] = carr[1] = carr[2] = carr[3] = carr[4] =
                    // int.class;
                    // carr[5] = StringTokenizer.class;
                    // Constructor cstr = null;
                    // cstr = cls.getConstructor(carr);
                    //
                    // // invoke constructor with starting coordinates
                    // Object oarr[] = new Object[6];
                    // //oarr[0] = this;
                    // oarr[0] = new Integer(x1);
                    // oarr[1] = new Integer(y1);
                    // oarr[2] = new Integer(x2);
                    // oarr[3] = new Integer(y2);
                    // oarr[4] = new Integer(f );
                    // oarr[5] = st;
                    // ce = (CircuitElm) cstr.newInstance(oarr);
                    CircuitElm newce = createCe(tint, x1, y1, x2, y2, f, st);
                    if (newce == null) {
                        System.out.println("unrecognized dump type: " + type);
                        break;
                    }
                    newce.setPoints();
                    elmList.addElement(newce);
                    // } catch (java.lang.reflect.InvocationTargetException ee)
                    // {
                    // ee.getTargetException().printStackTrace();
                    // break;
                } catch (Exception ee) {
                    ee.printStackTrace();
                    break;
                }
                break;
            }
            p += l;

        }
        gui.setPowerBarEnable();
        enableItems();
        // if (!retain)
        // handleResize(); // for scopes
        needAnalyze();
        if (centre)
            gui.centreCircuit();
    }

    void readHint(StringTokenizer st) {
        hintType = new Integer(st.nextToken()).intValue();
        hintItem1 = new Integer(st.nextToken()).intValue();
        hintItem2 = new Integer(st.nextToken()).intValue();
    }

    void readOptions(StringTokenizer st) {
        int flags = new Integer(st.nextToken()).intValue();
        // IES - remove inteaction
        gui.dotsCheckItem.setState((flags & 1) != 0);
        gui.smallGridCheckItem.setState((flags & 2) != 0);
        gui.voltsCheckItem.setState((flags & 4) == 0);
        gui.powerCheckItem.setState((flags & 8) == 8);
        gui.showValuesCheckItem.setState((flags & 16) == 0);
        timeStep = new Double(st.nextToken()).doubleValue();
        double sp = new Double(st.nextToken()).doubleValue();
        int sp2 = (int) (Math.log(10 * sp) * 24 + 61.5);
        // int sp2 = (int) (Math.log(sp)*24+1.5);
        gui.speedBar.setValue(sp2);
        gui.currentBar.setValue(new Integer(st.nextToken()).intValue());
        CircuitElm.voltageRange = new Double(st.nextToken()).doubleValue();

        try {
            gui.powerBar.setValue(new Integer(st.nextToken()).intValue());
        } catch (Exception e) {
        }
        gui.setGrid();
    }

    public int locateElm(CircuitElm elm) {
        int i;
        for (i = 0; i != elmList.size(); i++)
            if (elm == elmList.elementAt(i))
                return i;
        return -1;
    }

    void enableItems() {
        // if (powerCheckItem.getState()) {
        // powerBar.enable();
        // powerLabel.enable();
        // } else {
        // powerBar.disable();
        // powerLabel.disable();
        // }
        // enableUndoRedo();
    }

    // factors a matrix into upper and lower triangular matrices by
    // gaussian elimination. On entry, a[0..n-1][0..n-1] is the
    // matrix to be factored. ipvt[] returns an integer vector of pivot
    // indices, used in the lu_solve() routine.
    boolean lu_factor(double a[][], int n, int ipvt[]) {
        double scaleFactors[];
        int i, j, k;

        scaleFactors = new double[n];

        // divide each row by its largest element, keeping track of the
        // scaling factors
        for (i = 0; i != n; i++) {
            double largest = 0;
            for (j = 0; j != n; j++) {
                double x = Math.abs(a[i][j]);
                if (x > largest)
                    largest = x;
            }
            // if all zeros, it's a singular matrix
            if (largest == 0)
                return false;
            scaleFactors[i] = 1.0 / largest;
        }

        // use Crout's method; loop through the columns
        for (j = 0; j != n; j++) {

            // calculate upper triangular elements for this column
            for (i = 0; i != j; i++) {
                double q = a[i][j];
                for (k = 0; k != i; k++)
                    q -= a[i][k] * a[k][j];
                a[i][j] = q;
            }

            // calculate lower triangular elements for this column
            double largest = 0;
            int largestRow = -1;
            for (i = j; i != n; i++) {
                double q = a[i][j];
                for (k = 0; k != j; k++)
                    q -= a[i][k] * a[k][j];
                a[i][j] = q;
                double x = Math.abs(q);
                if (x >= largest) {
                    largest = x;
                    largestRow = i;
                }
            }

            // pivoting
            if (j != largestRow) {
                double x;
                for (k = 0; k != n; k++) {
                    x = a[largestRow][k];
                    a[largestRow][k] = a[j][k];
                    a[j][k] = x;
                }
                scaleFactors[largestRow] = scaleFactors[j];
            }

            // keep track of row interchanges
            ipvt[j] = largestRow;

            // avoid zeros
            if (a[j][j] == 0.0) {
                System.out.println("avoided zero");
                a[j][j] = 1e-18;
            }

            if (j != n - 1) {
                double mult = 1.0 / a[j][j];
                for (i = j + 1; i != n; i++)
                    a[i][j] *= mult;
            }
        }
        return true;
    }

    // Solves the set of n linear equations using a LU factorization
    // previously performed by lu_factor. On input, b[0..n-1] is the right
    // hand side of the equations, and on output, contains the solution.
    void lu_solve(double a[][], int n, int ipvt[], double b[]) {
        int i;

        // find first nonzero b element
        for (i = 0; i != n; i++) {
            int row = ipvt[i];

            double swap = b[row];
            b[row] = b[i];
            b[i] = swap;
            if (swap != 0)
                break;
        }

        int bi = i++;
        for (; i < n; i++) {
            int row = ipvt[i];
            int j;
            double tot = b[row];

            b[row] = b[i];
            // forward substitution using the lower triangular matrix
            for (j = bi; j < i; j++)
                tot -= a[i][j] * b[j];
            b[i] = tot;
        }
        for (i = n - 1; i >= 0; i--) {
            double tot = b[i];

            // back-substitution using the upper triangular matrix
            int j;
            for (j = i + 1; j != n; j++)
                tot -= a[i][j] * b[j];
            b[i] = tot / a[i][i];
        }
    }

    public void createNewLoadFile() {
        // This is a hack to fix what IMHO is a bug in the <INPUT FILE element
        // reloading the same file doesn't create a change event so importing
        // the same file twice
        // doesn't work unless you destroy the original input element and
        // replace it with a new one
        int idx = gui.verticalPanel.getWidgetIndex(loadFileInput);
        LoadFile newlf = new LoadFile(this);
        gui.verticalPanel.insert(newlf, idx);
        gui.verticalPanel.remove(idx + 1);
        loadFileInput = newlf;
    }

    public static CircuitElm createCe(int tint, int x1, int y1, int x2, int y2, int f, StringTokenizer st) {
        if (tint == 'g')
            return (CircuitElm) new GroundElm(x1, y1, x2, y2, f, st);
        if (tint == 'r')
            return (CircuitElm) new ResistorElm(x1, y1, x2, y2, f, st);
        if (tint == 'R')
            return (CircuitElm) new RailElm(x1, y1, x2, y2, f, st);
        if (tint == 's')
            return (CircuitElm) new SwitchElm(x1, y1, x2, y2, f, st);
        if (tint == 'S')
            return (CircuitElm) new Switch2Elm(x1, y1, x2, y2, f, st);
        if (tint == 't')
            return (CircuitElm) new TransistorElm(x1, y1, x2, y2, f, st);
        if (tint == 'w')
            return (CircuitElm) new WireElm(x1, y1, x2, y2, f, st);
        if (tint == 'c')
            return (CircuitElm) new CapacitorElm(x1, y1, x2, y2, f, st);
        if (tint == 'l')
            return (CircuitElm) new InductorElm(x1, y1, x2, y2, f, st);
        if (tint == 'v')
            return (CircuitElm) new VoltageElm(x1, y1, x2, y2, f, st);
        if (tint == 172)
            return (CircuitElm) new VarRailElm(x1, y1, x2, y2, f, st);
        if (tint == 174)
            return (CircuitElm) new PotElm(x1, y1, x2, y2, f, st);
        if (tint == 'O')
            return (CircuitElm) new OutputElm(x1, y1, x2, y2, f, st);
        if (tint == 'i')
            return (CircuitElm) new CurrentElm(x1, y1, x2, y2, f, st);
        if (tint == 'p')
            return (CircuitElm) new ProbeElm(x1, y1, x2, y2, f, st);
        if (tint == 'd')
            return (CircuitElm) new DiodeElm(x1, y1, x2, y2, f, st);
        if (tint == 'z')
            return (CircuitElm) new ZenerElm(x1, y1, x2, y2, f, st);
        if (tint == 170)
            return (CircuitElm) new SweepElm(x1, y1, x2, y2, f, st);
        if (tint == 162)
            return (CircuitElm) new LEDElm(x1, y1, x2, y2, f, st);
        if (tint == 'A')
            return (CircuitElm) new AntennaElm(x1, y1, x2, y2, f, st);
        if (tint == 'L')
            return (CircuitElm) new LogicInputElm(x1, y1, x2, y2, f, st);
        if (tint == 'M')
            return (CircuitElm) new LogicOutputElm(x1, y1, x2, y2, f, st);
        if (tint == 'T')
            return (CircuitElm) new TransformerElm(x1, y1, x2, y2, f, st);
        if (tint == 169)
            return (CircuitElm) new TappedTransformerElm(x1, y1, x2, y2, f, st);
        if (tint == 171)
            return (CircuitElm) new TransLineElm(x1, y1, x2, y2, f, st);
        if (tint == 178)
            return (CircuitElm) new RelayElm(x1, y1, x2, y2, f, st);
        if (tint == 'm')
            return (CircuitElm) new MemristorElm(x1, y1, x2, y2, f, st);
        if (tint == 187)
            return (CircuitElm) new SparkGapElm(x1, y1, x2, y2, f, st);
        if (tint == 200)
            return (CircuitElm) new AMElm(x1, y1, x2, y2, f, st);
        if (tint == 201)
            return (CircuitElm) new FMElm(x1, y1, x2, y2, f, st);
        if (tint == 181)
            return (CircuitElm) new LampElm(x1, y1, x2, y2, f, st);
        if (tint == 'a')
            return (CircuitElm) new OpAmpElm(x1, y1, x2, y2, f, st);
        if (tint == 'f')
            return (CircuitElm) new MosfetElm(x1, y1, x2, y2, f, st);
        if (tint == 'j')
            return (CircuitElm) new JfetElm(x1, y1, x2, y2, f, st);
        if (tint == 159)
            return (CircuitElm) new AnalogSwitchElm(x1, y1, x2, y2, f, st);
        if (tint == 160)
            return (CircuitElm) new AnalogSwitch2Elm(x1, y1, x2, y2, f, st);
        if (tint == 180)
            return (CircuitElm) new TriStateElm(x1, y1, x2, y2, f, st);
        if (tint == 182)
            return (CircuitElm) new SchmittElm(x1, y1, x2, y2, f, st);
        if (tint == 183)
            return (CircuitElm) new InvertingSchmittElm(x1, y1, x2, y2, f, st);
        if (tint == 177)
            return (CircuitElm) new SCRElm(x1, y1, x2, y2, f, st);
        if (tint == 203)
            return (CircuitElm) new DiacElm(x1, y1, x2, y2, f, st);
        if (tint == 206)
            return (CircuitElm) new TriacElm(x1, y1, x2, y2, f, st);
        if (tint == 173)
            return (CircuitElm) new TriodeElm(x1, y1, x2, y2, f, st);
        if (tint == 175)
            return (CircuitElm) new TunnelDiodeElm(x1, y1, x2, y2, f, st);
        if (tint == 179)
            return (CircuitElm) new CC2Elm(x1, y1, x2, y2, f, st);
        if (tint == 'I')
            return (CircuitElm) new InverterElm(x1, y1, x2, y2, f, st);
        if (tint == 151)
            return (CircuitElm) new NandGateElm(x1, y1, x2, y2, f, st);
        if (tint == 153)
            return (CircuitElm) new NorGateElm(x1, y1, x2, y2, f, st);
        if (tint == 150)
            return (CircuitElm) new AndGateElm(x1, y1, x2, y2, f, st);
        if (tint == 152)
            return (CircuitElm) new OrGateElm(x1, y1, x2, y2, f, st);
        if (tint == 154)
            return (CircuitElm) new XorGateElm(x1, y1, x2, y2, f, st);
        if (tint == 155)
            return (CircuitElm) new DFlipFlopElm(x1, y1, x2, y2, f, st);
        if (tint == 156)
            return (CircuitElm) new JKFlipFlopElm(x1, y1, x2, y2, f, st);
        if (tint == 157)
            return (CircuitElm) new SevenSegElm(x1, y1, x2, y2, f, st);
        if (tint == 184)
            return (CircuitElm) new MultiplexerElm(x1, y1, x2, y2, f, st);
        if (tint == 185)
            return (CircuitElm) new DeMultiplexerElm(x1, y1, x2, y2, f, st);
        if (tint == 189)
            return (CircuitElm) new SipoShiftElm(x1, y1, x2, y2, f, st);
        if (tint == 186)
            return (CircuitElm) new PisoShiftElm(x1, y1, x2, y2, f, st);
        if (tint == 161)
            return (CircuitElm) new PhaseCompElm(x1, y1, x2, y2, f, st);
        if (tint == 164)
            return (CircuitElm) new CounterElm(x1, y1, x2, y2, f, st);
        if (tint == 163)
            return (CircuitElm) new DecadeElm(x1, y1, x2, y2, f, st);
        if (tint == 165)
            return (CircuitElm) new TimerElm(x1, y1, x2, y2, f, st);
        if (tint == 166)
            return (CircuitElm) new DACElm(x1, y1, x2, y2, f, st);
        if (tint == 167)
            return (CircuitElm) new ADCElm(x1, y1, x2, y2, f, st);
        if (tint == 168)
            return (CircuitElm) new LatchElm(x1, y1, x2, y2, f, st);
        if (tint == 188)
            return (CircuitElm) new SeqGenElm(x1, y1, x2, y2, f, st);
        if (tint == 158)
            return (CircuitElm) new VCOElm(x1, y1, x2, y2, f, st);
        if (tint == 'b')
            return (CircuitElm) new BoxElm(x1, y1, x2, y2, f, st);
        if (tint == 'x')
            return (CircuitElm) new TextElm(x1, y1, x2, y2, f, st);
        if (tint == 193)
            return (CircuitElm) new TFlipFlopElm(x1, y1, x2, y2, f, st);
        if (tint == 197)
            return (CircuitElm) new SevenSegDecoderElm(x1, y1, x2, y2, f, st);
        if (tint == 196)
            return (CircuitElm) new FullAdderElm(x1, y1, x2, y2, f, st);
        if (tint == 195)
            return (CircuitElm) new HalfAdderElm(x1, y1, x2, y2, f, st);
        if (tint == 194)
            return (CircuitElm) new MonostableElm(x1, y1, x2, y2, f, st);
        if (tint == 202)
            return (CircuitElm) new LoudSpeakerElm(x1, y1, x2, y2, f, st);

        return null;
    }

    public static CircuitElm constructElement(String n, int x1, int y1) {
        if (n == "GroundElm")
            return (CircuitElm) new GroundElm(x1, y1);
        if (n == "ResistorElm")
            return (CircuitElm) new ResistorElm(x1, y1);
        if (n == "RailElm")
            return (CircuitElm) new RailElm(x1, y1);
        if (n == "SwitchElm")
            return (CircuitElm) new SwitchElm(x1, y1);
        if (n == "Switch2Elm")
            return (CircuitElm) new Switch2Elm(x1, y1);
        if (n == "NTransistorElm")
            return (CircuitElm) new NTransistorElm(x1, y1);
        if (n == "PTransistorElm")
            return (CircuitElm) new PTransistorElm(x1, y1);
        if (n == "WireElm")
            return (CircuitElm) new WireElm(x1, y1);
        if (n == "CapacitorElm")
            return (CircuitElm) new CapacitorElm(x1, y1);
        if (n == "Capacitor2Elm")
            return (CircuitElm) new Capacitor2Elm(x1, y1);
        if (n == "InductorElm")
            return (CircuitElm) new InductorElm(x1, y1);
        if (n == "DCVoltageElm")
            return (CircuitElm) new DCVoltageElm(x1, y1);
        if (n == "VarRailElm")
            return (CircuitElm) new VarRailElm(x1, y1);
        if (n == "PotElm")
            return (CircuitElm) new PotElm(x1, y1);
        if (n == "OutputElm")
            return (CircuitElm) new OutputElm(x1, y1);
        if (n == "CurrentElm")
            return (CircuitElm) new CurrentElm(x1, y1);
        if (n == "ProbeElm")
            return (CircuitElm) new ProbeElm(x1, y1);
        if (n == "DiodeElm")
            return (CircuitElm) new DiodeElm(x1, y1);
        if (n == "ZenerElm")
            return (CircuitElm) new ZenerElm(x1, y1);
        if (n == "ACVoltageElm")
            return (CircuitElm) new ACVoltageElm(x1, y1);
        if (n == "ACRailElm")
            return (CircuitElm) new ACRailElm(x1, y1);
        if (n == "SquareRailElm")
            return (CircuitElm) new SquareRailElm(x1, y1);
        if (n == "SweepElm")
            return (CircuitElm) new SweepElm(x1, y1);
        if (n == "LEDElm")
            return (CircuitElm) new LEDElm(x1, y1);
        if (n == "AntennaElm")
            return (CircuitElm) new AntennaElm(x1, y1);
        if (n == "LogicInputElm")
            return (CircuitElm) new LogicInputElm(x1, y1);
        if (n == "LogicOutputElm")
            return (CircuitElm) new LogicOutputElm(x1, y1);
        if (n == "TransformerElm")
            return (CircuitElm) new TransformerElm(x1, y1);
        if (n == "TappedTransformerElm")
            return (CircuitElm) new TappedTransformerElm(x1, y1);
        if (n == "TransLineElm")
            return (CircuitElm) new TransLineElm(x1, y1);
        if (n == "RelayElm")
            return (CircuitElm) new RelayElm(x1, y1);
        if (n == "MemristorElm")
            return (CircuitElm) new MemristorElm(x1, y1);
        if (n == "SparkGapElm")
            return (CircuitElm) new SparkGapElm(x1, y1);
        if (n == "ClockElm")
            return (CircuitElm) new ClockElm(x1, y1);
        if (n == "AMElm")
            return (CircuitElm) new AMElm(x1, y1);
        if (n == "FMElm")
            return (CircuitElm) new FMElm(x1, y1);
        if (n == "LampElm")
            return (CircuitElm) new LampElm(x1, y1);
        if (n == "PushSwitchElm")
            return (CircuitElm) new PushSwitchElm(x1, y1);
        if (n == "OpAmpElm")
            return (CircuitElm) new OpAmpElm(x1, y1);
        if (n == "OpAmpSwapElm")
            return (CircuitElm) new OpAmpSwapElm(x1, y1);
        if (n == "NMosfetElm")
            return (CircuitElm) new NMosfetElm(x1, y1);
        if (n == "PMosfetElm")
            return (CircuitElm) new PMosfetElm(x1, y1);
        if (n == "NJfetElm")
            return (CircuitElm) new NJfetElm(x1, y1);
        if (n == "PJfetElm")
            return (CircuitElm) new PJfetElm(x1, y1);
        if (n == "AnalogSwitchElm")
            return (CircuitElm) new AnalogSwitchElm(x1, y1);
        if (n == "AnalogSwitch2Elm")
            return (CircuitElm) new AnalogSwitch2Elm(x1, y1);
        if (n == "SchmittElm")
            return (CircuitElm) new SchmittElm(x1, y1);
        if (n == "InvertingSchmittElm")
            return (CircuitElm) new InvertingSchmittElm(x1, y1);
        if (n == "TriStateElm")
            return (CircuitElm) new TriStateElm(x1, y1);
        if (n == "SCRElm")
            return (CircuitElm) new SCRElm(x1, y1);
        if (n == "DiacElm")
            return (CircuitElm) new DiacElm(x1, y1);
        if (n == "TriacElm")
            return (CircuitElm) new TriacElm(x1, y1);
        if (n == "TriodeElm")
            return (CircuitElm) new TriodeElm(x1, y1);
        if (n == "TunnelDiodeElm")
            return (CircuitElm) new TunnelDiodeElm(x1, y1);
        if (n == "CC2Elm")
            return (CircuitElm) new CC2Elm(x1, y1);
        if (n == "CC2NegElm")
            return (CircuitElm) new CC2NegElm(x1, y1);
        if (n == "InverterElm")
            return (CircuitElm) new InverterElm(x1, y1);
        if (n == "NandGateElm")
            return (CircuitElm) new NandGateElm(x1, y1);
        if (n == "NorGateElm")
            return (CircuitElm) new NorGateElm(x1, y1);
        if (n == "AndGateElm")
            return (CircuitElm) new AndGateElm(x1, y1);
        if (n == "OrGateElm")
            return (CircuitElm) new OrGateElm(x1, y1);
        if (n == "XorGateElm")
            return (CircuitElm) new XorGateElm(x1, y1);
        if (n == "DFlipFlopElm")
            return (CircuitElm) new DFlipFlopElm(x1, y1);
        if (n == "JKFlipFlopElm")
            return (CircuitElm) new JKFlipFlopElm(x1, y1);
        if (n == "SevenSegElm")
            return (CircuitElm) new SevenSegElm(x1, y1);
        if (n == "MultiplexerElm")
            return (CircuitElm) new MultiplexerElm(x1, y1);
        if (n == "DeMultiplexerElm")
            return (CircuitElm) new DeMultiplexerElm(x1, y1);
        if (n == "SipoShiftElm")
            return (CircuitElm) new SipoShiftElm(x1, y1);
        if (n == "PisoShiftElm")
            return (CircuitElm) new PisoShiftElm(x1, y1);
        if (n == "PhaseCompElm")
            return (CircuitElm) new PhaseCompElm(x1, y1);
        if (n == "CounterElm")
            return (CircuitElm) new CounterElm(x1, y1);
        if (n == "DecadeElm")
            return (CircuitElm) new DecadeElm(x1, y1);
        if (n == "TimerElm")
            return (CircuitElm) new TimerElm(x1, y1);
        if (n == "DACElm")
            return (CircuitElm) new DACElm(x1, y1);
        if (n == "ADCElm")
            return (CircuitElm) new ADCElm(x1, y1);
        if (n == "LatchElm")
            return (CircuitElm) new LatchElm(x1, y1);
        if (n == "SeqGenElm")
            return (CircuitElm) new SeqGenElm(x1, y1);
        if (n == "VCOElm")
            return (CircuitElm) new VCOElm(x1, y1);
        if (n == "BoxElm")
            return (CircuitElm) new BoxElm(x1, y1);
        if (n == "TextElm")
            return (CircuitElm) new TextElm(x1, y1);
        if (n == "TFlipFlopElm")
            return (CircuitElm) new TFlipFlopElm(x1, y1);
        if (n == "SevenSegDecoderElm")
            return (CircuitElm) new SevenSegDecoderElm(x1, y1);
        if (n == "FullAdderElm")
            return (CircuitElm) new FullAdderElm(x1, y1);
        if (n == "HalfAdderElm")
            return (CircuitElm) new HalfAdderElm(x1, y1);
        if (n == "MonostableElm")
            return (CircuitElm) new MonostableElm(x1, y1);
        if (n == "LoudSpeakerElm")
            return (CircuitElm) new LoudSpeakerElm(x1, y1);

        return null;
    }

}