package org.apache.drill.exec.rpc;

import com.google.protobuf.Internal.EnumLite;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.Closeable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.drill.shaded.guava.com.google.common.base.Preconditions;
import org.apache.drill.shaded.guava.com.google.common.util.concurrent.AbstractFuture;
import com.google.protobuf.MessageLite;

/**
 * Manager all connections between two particular bits.
 */
public abstract class ReconnectingConnection<C extends ClientConnection, HS extends MessageLite> implements Closeable {

    static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ReconnectingConnection.class);

    private final AtomicReference<C> connectionHolder = new AtomicReference<C>();

    private final String host;

    private final int port;

    private final HS handshake;

    public ReconnectingConnection(HS handshake, String host, int port) {
        Preconditions.checkNotNull(host);
        Preconditions.checkArgument(port > 0);
        this.host = host;
        this.port = port;
        this.handshake = handshake;
    }

    protected abstract BasicClient<?, C, HS, ?> getNewClient();

    public <T extends MessageLite, E extends EnumLite, M extends MessageLite, R extends RpcCommand<T, C, E, M>> void runCommand(R cmd) {
        // if(logger.isDebugEnabled()) logger.debug(String.format("Running command %s sending to host %s:%d", cmd, host, port));
        C connection = connectionHolder.get();
        if (connection != null) {
            if (connection.isActive()) {
                cmd.connectionAvailable(connection);
                // logger.debug("Connection available and active, command run inline.");
                return;
            } else {
                // remove the old connection. (don't worry if we fail since someone else should have done it.
                connectionHolder.compareAndSet(connection, null);
            }
        }
        /**
         * We've arrived here without a connection, let's make sure only one of us makes a connection. (fyi, another
         * endpoint could create a reverse connection
         */
        synchronized (this) {
            connection = connectionHolder.get();
            if (connection != null) {
                cmd.connectionAvailable(connection);
            } else {
                // logger.debug("No connection active, opening client connection.");
                BasicClient<?, C, HS, ?> client = getNewClient();
                ConnectionListeningFuture<T, E, M> future = new ConnectionListeningFuture<>(cmd);
                client.connectAsClient(future, handshake, host, port);
                future.waitAndRun();
                // logger.debug("Connection available and active, command now being run inline.");
            }
            return;
        }
    }

    public class ConnectionListeningFuture<R extends MessageLite, E extends EnumLite, M extends MessageLite> extends AbstractFuture<C> implements RpcConnectionHandler<C> {

        private RpcCommand<R, C, E, M> cmd;

        public ConnectionListeningFuture(RpcCommand<R, C, E, M> cmd) {
            super();
            this.cmd = cmd;
        }

        /**
         * Called by
         */
        public void waitAndRun() {
            boolean isInterrupted = false;
            // We want to wait for at least 120 secs when interrupts occur. Establishing a connection fails/succeeds quickly,
            // So there is no point propagating the interruption as failure immediately.
            long remainingWaitTimeMills = 120000;
            long startTime = System.currentTimeMillis();
            while (true) {
                try {
                    C connection = this.get(remainingWaitTimeMills, TimeUnit.MILLISECONDS);
                    if (connection == null) {
                    } else {
                        cmd.connectionSucceeded(connection);
                        // logger.debug("Finished connection succeeded activity.");
                    }
                    break;
                } catch (final InterruptedException interruptEx) {
                    remainingWaitTimeMills -= (System.currentTimeMillis() - startTime);
                    startTime = System.currentTimeMillis();
                    isInterrupted = true;
                    if (remainingWaitTimeMills < 1) {
                        cmd.connectionFailed(FailureType.CONNECTION, interruptEx);
                        break;
                    }
                    // Ignore the interrupt and continue to wait until we elapse remainingWaitTimeMills.
                } catch (final ExecutionException | TimeoutException ex) {
                    logger.error("Failed to establish connection", ex);
                    cmd.connectionFailed(FailureType.CONNECTION, ex);
                    break;
                }
            }
            if (isInterrupted) {
                // Preserve evidence that the interruption occurred so that code higher up on the call stack can learn of the
                // interruption and respond to it if it wants to.
                Thread.currentThread().interrupt();
            }
        }

        @Override
        public void connectionFailed(FailureType type, Throwable t) {
            set(null);
            cmd.connectionFailed(type, t);
        }

        @Override
        public void connectionSucceeded(C incoming) {
            C connection = connectionHolder.get();
            while (true) {
                boolean setted = connectionHolder.compareAndSet(null, incoming);
                if (setted) {
                    connection = incoming;
                    break;
                }
                connection = connectionHolder.get();
                if (connection != null) {
                    break;
                }
            }
            if (connection != incoming) {
                // close the incoming because another channel was created in the mean time (unless this is a self connection).
                logger.debug("Closing incoming connection because a connection was already set.");
                incoming.getChannel().close();
            }
            set(connection);
        }
    }

    /**
     * Factory for close handlers *
     */
    public class CloseHandlerCreator {

        public GenericFutureListener<ChannelFuture> getHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            return new CloseHandler(connection, parent);
        }
    }

    /**
     * Listens for connection closes and clears connection holder.
     */
    protected class CloseHandler implements GenericFutureListener<ChannelFuture> {

        private C connection;

        private GenericFutureListener<ChannelFuture> parent;

        public CloseHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            super();
            this.connection = connection;
            this.parent = parent;
        }

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            connectionHolder.compareAndSet(connection, null);
            parent.operationComplete(future);
        }
    }

    public CloseHandlerCreator getCloseHandlerCreator() {
        return new CloseHandlerCreator();
    }

    public void addExternalConnection(C connection) {
        // if the connection holder is not set, set it to this incoming connection. We'll simply ignore if already set.
        this.connectionHolder.compareAndSet(null, connection);
    }

    @Override
    public void close() {
        C c = connectionHolder.

        if (c != null) {
            c.getChannel().close();
        }
    }
}


if (connection != incoming) {
                // close the incoming because another channel was created in the mean time (unless this is a self connection).
                logger.debug("Closing incoming connection because a connection was already set.");
                incoming.getChannel().close();
            }

package org.apache.drill.exec.rpc;

import com.google.protobuf.Internal.EnumLite;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.Closeable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.drill.shaded.guava.com.google.common.base.Preconditions;
import org.apache.drill.shaded.guava.com.google.common.util.concurrent.AbstractFuture;
import com.google.protobuf.MessageLite;

/**
 * Manager all connections between two particular bits.
 */
public abstract class ReconnectingConnection<C extends ClientConnection, HS extends MessageLite> implements Closeable {

    static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ReconnectingConnection.class);

    private final AtomicReference<C> connectionHolder = new AtomicReference<C>();

    private final String host;

    private final int port;

    private final HS handshake;

    public ReconnectingConnection(HS handshake, String host, int port) {
        Preconditions.checkNotNull(host);
        Preconditions.checkArgument(port > 0);
        this.host = host;
        this.port = port;
        this.handshake = handshake;
    }

    protected abstract BasicClient<?, C, HS, ?> getNewClient();

    public <T extends MessageLite, E extends EnumLite, M extends MessageLite, R extends RpcCommand<T, C, E, M>> void runCommand(R cmd) {
        // if(logger.isDebugEnabled()) logger.debug(String.format("Running command %s sending to host %s:%d", cmd, host, port));
        C connection = connectionHolder.get();
        if (connection != null) {
            if (connection.isActive()) {
                cmd.connectionAvailable(connection);
                // logger.debug("Connection available and active, command run inline.");
                return;
            } else {
                // remove the old connection. (don't worry if we fail since someone else should have done it.
                connectionHolder.compareAndSet(connection, null);
            }
        }
        /**
         * We've arrived here without a connection, let's make sure only one of us makes a connection. (fyi, another
         * endpoint could create a reverse connection
         */
        synchronized (this) {
            connection = connectionHolder.get();
            if (connection != null) {
                cmd.connectionAvailable(connection);
            } else {
                // logger.debug("No connection active, opening client connection.");
                BasicClient<?, C, HS, ?> client = getNewClient();
                ConnectionListeningFuture<T, E, M> future = new ConnectionListeningFuture<>(cmd);
                client.connectAsClient(future, handshake, host, port);
                future.waitAndRun();
                // logger.debug("Connection available and active, command now being run inline.");
            }
            return;
        }
    }

    public class ConnectionListeningFuture<R extends MessageLite, E extends EnumLite, M extends MessageLite> extends AbstractFuture<C> implements RpcConnectionHandler<C> {

        private RpcCommand<R, C, E, M> cmd;

        public ConnectionListeningFuture(RpcCommand<R, C, E, M> cmd) {
            super();
            this.cmd = cmd;
        }

        /**
         * Called by
         */
        public void waitAndRun() {
            boolean isInterrupted = false;
            // We want to wait for at least 120 secs when interrupts occur. Establishing a connection fails/succeeds quickly,
            // So there is no point propagating the interruption as failure immediately.
            long remainingWaitTimeMills = 120000;
            long startTime = System.currentTimeMillis();
            while (true) {
                try {
                    C connection = this.get(remainingWaitTimeMills, TimeUnit.MILLISECONDS);
                    if (connection == null) {
                    } else {
                        cmd.connectionSucceeded(connection);
                        // logger.debug("Finished connection succeeded activity.");
                    }
                    break;
                } catch (final InterruptedException interruptEx) {
                    remainingWaitTimeMills -= (System.currentTimeMillis() - startTime);
                    startTime = System.currentTimeMillis();
                    isInterrupted = true;
                    if (remainingWaitTimeMills < 1) {
                        cmd.connectionFailed(FailureType.CONNECTION, interruptEx);
                        break;
                    }
                    // Ignore the interrupt and continue to wait until we elapse remainingWaitTimeMills.
                } catch (final ExecutionException | TimeoutException ex) {
                    logger.error("Failed to establish connection", ex);
                    cmd.connectionFailed(FailureType.CONNECTION, ex);
                    break;
                }
            }
            if (isInterrupted) {
                // Preserve evidence that the interruption occurred so that code higher up on the call stack can learn of the
                // interruption and respond to it if it wants to.
                Thread.currentThread().interrupt();
            }
        }

        @Override
        public void connectionFailed(FailureType type, Throwable t) {
            set(null);
            cmd.connectionFailed(type, t);
        }

        @Override
        public void connectionSucceeded(C incoming) {
            C connection = connectionHolder.get();
            while (true) {
                boolean setted = connectionHolder.compareAndSet(null, incoming);
                if (setted) {
                    connection = incoming;
                    break;
                }
                connection = connectionHolder.get();
                if (connection != null) {
                    break;
                }
            }

            set(connection);
        }
    }

    /**
     * Factory for close handlers *
     */
    public class CloseHandlerCreator {

        public GenericFutureListener<ChannelFuture> getHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            return new CloseHandler(connection, parent);
        }
    }

    /**
     * Listens for connection closes and clears connection holder.
     */
    protected class CloseHandler implements GenericFutureListener<ChannelFuture> {

        private C connection;

        private GenericFutureListener<ChannelFuture> parent;

        public CloseHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            super();
            this.connection = connection;
            this.parent = parent;
        }

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            connectionHolder.compareAndSet(connection, null);
            parent.operationComplete(future);
        }
    }

    public CloseHandlerCreator getCloseHandlerCreator() {
        return new CloseHandlerCreator();
    }

    public void addExternalConnection(C connection) {
        // if the connection holder is not set, set it to this incoming connection. We'll simply ignore if already set.
        this.connectionHolder.compareAndSet(null, connection);
    }

    @Override
    public void close() {
        C c = connectionHolder.getAndSet(null);
        if (c != null) {
            c.getChannel().close();
        }
    }
}


while (true) {
                boolean setted = connectionHolder.compareAndSet(null, incoming);
                if (setted) {
                    connection = incoming;
                    break;
                }
                connection = connectionHolder.get();
                if (connection != null) {
                    break;
                }
            }

package org.apache.drill.exec.rpc;

import com.google.protobuf.Internal.EnumLite;
import io.netty.channel.ChannelFuture;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.Closeable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.drill.shaded.guava.com.google.common.base.Preconditions;
import org.apache.drill.shaded.guava.com.google.common.util.concurrent.AbstractFuture;
import com.google.protobuf.MessageLite;

/**
 * Manager all connections between two particular bits.
 */
public abstract class ReconnectingConnection<C extends ClientConnection, HS extends MessageLite> implements Closeable {

    static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ReconnectingConnection.class);

    private final AtomicReference<C> connectionHolder = new AtomicReference<C>();

    private final String host;

    private final int port;

    private final HS handshake;

    public ReconnectingConnection(HS handshake, String host, int port) {
        Preconditions.checkNotNull(host);
        Preconditions.checkArgument(port > 0);
        this.host = host;
        this.port = port;
        this.handshake = handshake;
    }

    protected abstract BasicClient<?, C, HS, ?> getNewClient();

    public <T extends MessageLite, E extends EnumLite, M extends MessageLite, R extends RpcCommand<T, C, E, M>> void runCommand(R cmd) {
        // if(logger.isDebugEnabled()) logger.debug(String.format("Running command %s sending to host %s:%d", cmd, host, port));
        C connection = connectionHolder.get();
        if (connection != null) {
            if (connection.isActive()) {
                cmd.connectionAvailable(connection);
                // logger.debug("Connection available and active, command run inline.");
                return;
            } else {
                // remove the old connection. (don't worry if we fail since someone else should have done it.
                connectionHolder.compareAndSet(connection, null);
            }
        }
        /**
         * We've arrived here without a connection, let's make sure only one of us makes a connection. (fyi, another
         * endpoint could create a reverse connection
         */
        synchronized (this) {
            connection = connectionHolder.get();
            if (connection != null) {
                cmd.connectionAvailable(connection);
            } else {
                // logger.debug("No connection active, opening client connection.");
                BasicClient<?, C, HS, ?> client = getNewClient();
                ConnectionListeningFuture<T, E, M> future = new ConnectionListeningFuture<>(cmd);
                client.connectAsClient(future, handshake, host, port);
                future.waitAndRun();
                // logger.debug("Connection available and active, command now being run inline.");
            }
            return;
        }
    }

    public class ConnectionListeningFuture<R extends MessageLite, E extends EnumLite, M extends MessageLite> extends AbstractFuture<C> implements RpcConnectionHandler<C> {

        private RpcCommand<R, C, E, M> cmd;

        public ConnectionListeningFuture(RpcCommand<R, C, E, M> cmd) {
            super();
            this.cmd = cmd;
        }

        /**
         * Called by
         */
        public void waitAndRun() {
            boolean isInterrupted = false;
            // We want to wait for at least 120 secs when interrupts occur. Establishing a connection fails/succeeds quickly,
            // So there is no point propagating the interruption as failure immediately.
            long remainingWaitTimeMills = 120000;
            long startTime = System.currentTimeMillis();
            while (true) {
                try {
                    C connection = this.get(remainingWaitTimeMills, TimeUnit.MILLISECONDS);
                    if (connection == null) {
                    } else {
                        cmd.connectionSucceeded(connection);
                        // logger.debug("Finished connection succeeded activity.");
                    }
                    break;
                } catch (final InterruptedException interruptEx) {
                    remainingWaitTimeMills -= (System.currentTimeMillis() - startTime);
                    startTime = System.currentTimeMillis();
                    isInterrupted = true;
                    if (remainingWaitTimeMills < 1) {
                        cmd.connectionFailed(FailureType.CONNECTION, interruptEx);
                        break;
                    }
                    // Ignore the interrupt and continue to wait until we elapse remainingWaitTimeMills.
                } catch (final ExecutionException | TimeoutException ex) {
                    logger.error("Failed to establish connection", ex);
                    cmd.connectionFailed(FailureType.CONNECTION, ex);
                    break;
                }
            }
            if (isInterrupted) {
                // Preserve evidence that the interruption occurred so that code higher up on the call stack can learn of the
                // interruption and respond to it if it wants to.
                Thread.currentThread().interrupt();
            }
        }

        @Override
        public void connectionFailed(FailureType type, Throwable t) {
            set(null);
            cmd.connectionFailed(type, t);
        }

        @Override
        public void connectionSucceeded(C incoming) {
            C connection = connectionHolder.get();

            if (connection != incoming) {
                // close the incoming because another channel was created in the mean time (unless this is a self connection).
                logger.debug("Closing incoming connection because a connection was already set.");
                incoming.getChannel().close();
            }
            set(connection);
        }
    }

    /**
     * Factory for close handlers *
     */
    public class CloseHandlerCreator {

        public GenericFutureListener<ChannelFuture> getHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            return new CloseHandler(connection, parent);
        }
    }

    /**
     * Listens for connection closes and clears connection holder.
     */
    protected class CloseHandler implements GenericFutureListener<ChannelFuture> {

        private C connection;

        private GenericFutureListener<ChannelFuture> parent;

        public CloseHandler(C connection, GenericFutureListener<ChannelFuture> parent) {
            super();
            this.connection = connection;
            this.parent = parent;
        }

        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            connectionHolder.compareAndSet(connection, null);
            parent.operationComplete(future);
        }
    }

    public CloseHandlerCreator getCloseHandlerCreator() {
        return new CloseHandlerCreator();
    }

    public void addExternalConnection(C connection) {
        // if the connection holder is not set, set it to this incoming connection. We'll simply ignore if already set.
        this.connectionHolder.compareAndSet(null, connection);
    }

    @Override
    public void close() {
        C c = connectionHolder.getAndSet(null);
        if (c != null) {
            c.getChannel().close();
        }
    }
}


package panda.interpreter.syntax.scope;

import panda.interpreter.architecture.dynamic.AbstractExecutableStatement;
import panda.interpreter.architecture.expression.Expression;
import panda.interpreter.source.Localizable;
import panda.interpreter.runtime.ProcessStack;

public class StandaloneExpression extends AbstractExecutableStatement {

    private final Expression expression;

    public StandaloneExpression(Localizable localizable, Expression expression) {
        super(localizable);
        this.expression = expression;
    }

    @Override
    public Object execute(ProcessStack stack, Object instance) throws Exception {
        return expression.evaluate(stack, instance);
    }


{
        return expression.evaluate(stack, instance);
    }

package panda.interpreter.syntax.scope;

import panda.interpreter.architecture.dynamic.AbstractExecutableStatement;
import panda.interpreter.architecture.expression.Expression;
import panda.interpreter.source.Localizable;
import panda.interpreter.runtime.ProcessStack;

public class StandaloneExpression extends AbstractExecutableStatement {

    private final Expression expression;

    public StandaloneExpression(Localizable localizable, Expression expression) {
        super(localizable);
        this.expression = expression;
    }

    @Override
    public Object execute(ProcessStack stack, Object instance) throws Exception

    public Expression getExpression() {
        return expression;
    }
}


package panda.interpreter.syntax.scope;

import panda.interpreter.architecture.dynamic.AbstractExecutableStatement;
import panda.interpreter.architecture.expression.Expression;
import panda.interpreter.source.Localizable;
import panda.interpreter.runtime.ProcessStack;

public class StandaloneExpression extends AbstractExecutableStatement {

    private final Expression expression;

    public StandaloneExpression(Localizable localizable, Expression expression) {
        super(localizable);
        this.expression = expression;
    }

    @Override
    public Object execute(ProcessStack stack, Object instance) throws Exception {
        return expression.evaluate(stack, instance);
    }

    public Expression getExpression() {
        return expressi


package com.udacity.gamedev.icicles;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;

public class Player {

    public static final String TAG = Player.class.getName();

    Vector2 position;

    Viewport viewport;

    // TODO: Add counter for number of deaths
    int deaths;

    public Player(Viewport viewport) {
        this.viewport = viewport;
        // TODO: Set number of deaths to zero
        deaths = 0;
        init();
    }

{
        position = new Vector2(viewport.getWorldWidth() / 2, Constants.PLAYER_HEAD_HEIGHT);
    }

    public void update(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            position.x -= delta * Constants.PLAYER_MOVEMENT_SPEED;
        } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            position.x += delta * Constants.PLAYER_MOVEMENT_SPEED;
        }
        float accelerometerInput = -Gdx.input.getAccelerometerY() / (Constants.GRAVITATIONAL_ACCELERATION * Constants.ACCELEROMETER_SENSITIVITY);
        position.x += -delta * accelerometerInput * Constants.PLAYER_MOVEMENT_SPEED;
        ensureInBounds();
    }

    private void ensureInBounds() {
        if (position.x - Constants.PLAYER_HEAD_RADIUS < 0) {
            position.x = Constants.PLAYER_HEAD_RADIUS;
        }
        if (position.x + Constants.PLAYER_HEAD_RADIUS > viewport.getWorldWidth()) {
            position.x = viewport.getWorldWidth() - Constants.PLAYER_HEAD_RADIUS;
        }
    }

    public boolean hitByIcicle(Icicles icicles) {
        boolean isHit = false;
        for (Icicle icicle : icicles.icicleList) {
            if (icicle.position.dst(position) < Constants.PLAYER_HEAD_RADIUS) {
                isHit = true;
            }
        }
        // TODO: If the player was hit, increment death counter
        if (isHit) {
            deaths += 1;
        }
        return isHit;
    }

    public void render(ShapeRenderer renderer) {
        renderer.setColor(Constants.PLAYER_COLOR);
        renderer.set(ShapeType.Filled);
        renderer.circle(position.x, position.y, Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_HEAD_SEGMENTS);
        Vector2 torsoTop = new Vector2(position.x, position.y - Constants.PLAYER_HEAD_RADIUS);
        Vector2 torsoBottom = new Vector2(torsoTop.x, torsoTop.y - 2 * Constants.PLAYER_HEAD_RADIUS);
        renderer.rectLine(torsoTop, torsoBottom, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x + Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x - Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x + Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x - Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
    }
}


{
        if (position.x - Constants.PLAYER_HEAD_RADIUS < 0) {
            position.x = Constants.PLAYER_HEAD_RADIUS;
        }
        if (position.x + Constants.PLAYER_HEAD_RADIUS > viewport.getWorldWidth()) {
            position.x = viewport.getWorldWidth() - Constants.PLAYER_HEAD_RADIUS;
        }
    }

package com.udacity.gamedev.icicles;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;

public class Player {

    public static final String TAG = Player.class.getName();

    Vector2 position;

    Viewport viewport;

    // TODO: Add counter for number of deaths
    int deaths;

    public Player(Viewport viewport) {
        this.viewport = viewport;
        // TODO: Set number of deaths to zero
        deaths = 0;
        init();
    }

    public void init() {
        position = new Vector2(viewport.getWorldWidth() / 2, Constants.PLAYER_HEAD_HEIGHT);
    }

    public void update(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            position.x -= delta * Constants.PLAYER_MOVEMENT_SPEED;
        } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            position.x += delta * Constants.PLAYER_MOVEMENT_SPEED;
        }
        float accelerometerInput = -Gdx.input.getAccelerometerY() / (Constants.GRAVITATIONAL_ACCELERATION * Constants.ACCELEROMETER_SENSITIVITY);
        position.x += -delta * accelerometerInput * Constants.PLAYER_MOVEMENT_SPEED;
        ensureInBounds();
    }

    private void ensureInBounds()

    public boolean hitByIcicle(Icicles icicles) {
        boolean isHit = false;
        for (Icicle icicle : icicles.icicleList) {
            if (icicle.position.dst(position) < Constants.PLAYER_HEAD_RADIUS) {
                isHit = true;
            }
        }
        // TODO: If the player was hit, increment death counter
        if (isHit) {
            deaths += 1;
        }
        return isHit;
    }

    public void render(ShapeRenderer renderer) {
        renderer.setColor(Constants.PLAYER_COLOR);
        renderer.set(ShapeType.Filled);
        renderer.circle(position.x, position.y, Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_HEAD_SEGMENTS);
        Vector2 torsoTop = new Vector2(position.x, position.y - Constants.PLAYER_HEAD_RADIUS);
        Vector2 torsoBottom = new Vector2(torsoTop.x, torsoTop.y - 2 * Constants.PLAYER_HEAD_RADIUS);
        renderer.rectLine(torsoTop, torsoBottom, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x + Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x - Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x + Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x - Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
    }
}


Top.x - Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);

package com.udacity.gamedev.icicles;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;

public class Player {

    public static final String TAG = Player.class.getName();

    Vector2 position;

    Viewport viewport;

    // TODO: Add counter for number of deaths
    int deaths;

    public Player(Viewport viewport) {
        this.viewport = viewport;
        // TODO: Set number of deaths to zero
        deaths = 0;
        init();
    }

    public void init() {
        position = new Vector2(viewport.getWorldWidth() / 2, Constants.PLAYER_HEAD_HEIGHT);
    }

    public void update(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            position.x -= delta * Constants.PLAYER_MOVEMENT_SPEED;
        } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            position.x += delta * Constants.PLAYER_MOVEMENT_SPEED;
        }
        float accelerometerInput = -Gdx.input.getAccelerometerY() / (Constants.GRAVITATIONAL_ACCELERATION * Constants.ACCELEROMETER_SENSITIVITY);
        position.x += -delta * accelerometerInput * Constants.PLAYER_MOVEMENT_SPEED;
        ensureInBounds();
    }

    private void ensureInBounds() {
        if (position.x - Constants.PLAYER_HEAD_RADIUS < 0) {
            position.x = Constants.PLAYER_HEAD_RADIUS;
        }
        if (position.x + Constants.PLAYER_HEAD_RADIUS > viewport.getWorldWidth()) {
            position.x = viewport.getWorldWidth() - Constants.PLAYER_HEAD_RADIUS;
        }
    }

    public boolean hitByIcicle(Icicles icicles) {
        boolean isHit = false;
        for (Icicle icicle : icicles.icicleList) {
            if (icicle.position.dst(position) < Constants.PLAYER_HEAD_RADIUS) {
                isHit = true;
            }
        }
        // TODO: If the player was hit, increment death counter
        if (isHit) {
            deaths += 1;
        }
        return isHit;
    }

    public void render(ShapeRenderer renderer) {
        renderer.setColor(Constants.PLAYER_COLOR);
        renderer.set(ShapeType.Filled);
        renderer.circle(position.x, position.y, Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_HEAD_SEGMENTS);
        Vector2 torsoTop = new Vector2(position.x, position.y - Constants.PLAYER_HEAD_RADIUS);
        Vector2 torsoBottom = new Vector2(torsoTop.x, torsoTop.y - 2 * Constants.PLAYER_HEAD_RADIUS);
        renderer.rectLine(torsoTop, torsoBottom, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x + Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torso

        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x + Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x - Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
    }
}


if (position.x + Constants.PLAYER_HEAD_RADIUS > viewport.getWorldWidth()) {
            position.x = viewport.getWorldWidth() - Constants.PLAYER_HEAD_RADIUS;
        }

package com.udacity.gamedev.icicles;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.Viewport;

public class Player {

    public static final String TAG = Player.class.getName();

    Vector2 position;

    Viewport viewport;

    // TODO: Add counter for number of deaths
    int deaths;

    public Player(Viewport viewport) {
        this.viewport = viewport;
        // TODO: Set number of deaths to zero
        deaths = 0;
        init();
    }

    public void init() {
        position = new Vector2(viewport.getWorldWidth() / 2, Constants.PLAYER_HEAD_HEIGHT);
    }

    public void update(float delta) {
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            position.x -= delta * Constants.PLAYER_MOVEMENT_SPEED;
        } else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            position.x += delta * Constants.PLAYER_MOVEMENT_SPEED;
        }
        float accelerometerInput = -Gdx.input.getAccelerometerY() / (Constants.GRAVITATIONAL_ACCELERATION * Constants.ACCELEROMETER_SENSITIVITY);
        position.x += -delta * accelerometerInput * Constants.PLAYER_MOVEMENT_SPEED;
        ensureInBounds();
    }

    private void ensureInBounds() {
        if (position.x - Constants.PLAYER_HEAD_RADIUS < 0) {
            position.x = Constants.PLAYER_HEAD_RADIUS;
        }

    }

    public boolean hitByIcicle(Icicles icicles) {
        boolean isHit = false;
        for (Icicle icicle : icicles.icicleList) {
            if (icicle.position.dst(position) < Constants.PLAYER_HEAD_RADIUS) {
                isHit = true;
            }
        }
        // TODO: If the player was hit, increment death counter
        if (isHit) {
            deaths += 1;
        }
        return isHit;
    }

    public void render(ShapeRenderer renderer) {
        renderer.setColor(Constants.PLAYER_COLOR);
        renderer.set(ShapeType.Filled);
        renderer.circle(position.x, position.y, Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_HEAD_SEGMENTS);
        Vector2 torsoTop = new Vector2(position.x, position.y - Constants.PLAYER_HEAD_RADIUS);
        Vector2 torsoBottom = new Vector2(torsoTop.x, torsoTop.y - 2 * Constants.PLAYER_HEAD_RADIUS);
        renderer.rectLine(torsoTop, torsoBottom, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x + Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoTop.x, torsoTop.y, torsoTop.x - Constants.PLAYER_HEAD_RADIUS, torsoTop.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x + Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
        renderer.rectLine(torsoBottom.x, torsoBottom.y, torsoBottom.x - Constants.PLAYER_HEAD_RADIUS, torsoBottom.y - Constants.PLAYER_HEAD_RADIUS, Constants.PLAYER_LIMB_WIDTH);
    }
}


public void componentShown(ComponentEvent e)

package wprover;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.net.URL;

class JExPanel extends JPanel implements ActionListener, MouseListener, MouseMotionListener, ComponentListener {

    drawProcess dp;

    static ImageIcon icoa;

    static ImageIcon icos;

    JToggleButton button;

    Timer timer = null;

    public void paint(Graphics g) {
        super.paint(g);
        if (dp != null)
            dp.paintPoint(g);
    }

    public JExPanel() {
        super();
        this.setLayout(null);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.addComponentListener(this);
        this.setBackground(new Color(228, 236, 252));
        URL imageURL = GExpert.class.getResource("images/animate_start.gif");
        ImageIcon image = new ImageIcon(imageURL);
        URL imageURL1 = GExpert.class.getResource("images/animate_stop.gif");
        ImageIcon image1 = new ImageIcon(imageURL1);
        button = new JToggleButton(image) {

            public Dimension getPreferredSize() {
                return new Dimension(30, 28);
            }
        };
        this.add(button);
        button.addActionListener(this);
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
        button.setSelectedIcon(image1);
    }

    public static void setAinimateIcon(ImageIcon ico1, ImageIcon ico2) {
        icoa = ico1;
        icos = ico2;
    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 400);
    }

    public void setdrawP(drawProcess dp) {
        this.dp = dp;
        if (timer != null)
            timer.stop();
        if (dp.animate != null) {
            AnimateC ant = dp.animate;
            if (timer == null)
                timer = new Timer(ant.getInitValue(), this);
            else
                timer.setDelay(ant.getInitValue());
            timer.start();
            button.setIcon(icos);
            button.setVisible(true);
        } else
            button.setVisible(false);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button) {
            if (!timer.isRunning()) {
                dp.animationStart();
                button.setIcon(icos);
                timer.start();
            } else {
                dp.animationStop();
                button.setIcon(icoa);
                timer.stop();
            }
        } else if (e.getSource() == timer) {
            dp.animationOntime();
            this.repaint();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() > 1)
            dp.DWMouseDbClick(e.getX(), e.getY());
        if (e.getButton() == MouseEvent.BUTTON3)
            dp.DWMouseRightClick(e.getX(), e.getY());
    }

    public void mousePressed(MouseEvent e) {
        dp.DWButtonDown(e.getX(), e.getY());
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
        dp.DWButtonUp(e.getX(), e.getY());
        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        dp.DWMouseDrag(e.getX(), e.getY());
        this.repaint();
    }

    public void mouseMoved(MouseEvent e) {
        dp.DWMouseMove(e.getX(), e.getY());
        this.repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        dp.paintPoint(g);
    }

    public void componentResized(ComponentEvent e) {
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
    }

    public void componentMoved(ComponentEvent e) {
    }

{
    }

    public void componentHidden(ComponentEvent e) {
        timer.stop();
    }
}


{
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
    }

package wprover;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.net.URL;

class JExPanel extends JPanel implements ActionListener, MouseListener, MouseMotionListener, ComponentListener {

    drawProcess dp;

    static ImageIcon icoa;

    static ImageIcon icos;

    JToggleButton button;

    Timer timer = null;

    public void paint(Graphics g) {
        super.paint(g);
        if (dp != null)
            dp.paintPoint(g);
    }

    public JExPanel() {
        super();
        this.setLayout(null);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.addComponentListener(this);
        this.setBackground(new Color(228, 236, 252));
        URL imageURL = GExpert.class.getResource("images/animate_start.gif");
        ImageIcon image = new ImageIcon(imageURL);
        URL imageURL1 = GExpert.class.getResource("images/animate_stop.gif");
        ImageIcon image1 = new ImageIcon(imageURL1);
        button = new JToggleButton(image) {

            public Dimension getPreferredSize() {
                return new Dimension(30, 28);
            }
        };
        this.add(button);
        button.addActionListener(this);
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
        button.setSelectedIcon(image1);
    }

    public static void setAinimateIcon(ImageIcon ico1, ImageIcon ico2) {
        icoa = ico1;
        icos = ico2;
    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 400);
    }

    public void setdrawP(drawProcess dp) {
        this.dp = dp;
        if (timer != null)
            timer.stop();
        if (dp.animate != null) {
            AnimateC ant = dp.animate;
            if (timer == null)
                timer = new Timer(ant.getInitValue(), this);
            else
                timer.setDelay(ant.getInitValue());
            timer.start();
            button.setIcon(icos);
            button.setVisible(true);
        } else
            button.setVisible(false);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button) {
            if (!timer.isRunning()) {
                dp.animationStart();
                button.setIcon(icos);
                timer.start();
            } else {
                dp.animationStop();
                button.setIcon(icoa);
                timer.stop();
            }
        } else if (e.getSource() == timer) {
            dp.animationOntime();
            this.repaint();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() > 1)
            dp.DWMouseDbClick(e.getX(), e.getY());
        if (e.getButton() == MouseEvent.BUTTON3)
            dp.DWMouseRightClick(e.getX(), e.getY());
    }

    public void mousePressed(MouseEvent e) {
        dp.DWButtonDown(e.getX(), e.getY());
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
        dp.DWButtonUp(e.getX(), e.getY());
        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        dp.DWMouseDrag(e.getX(), e.getY());
        this.repaint();
    }

    public void mouseMoved(MouseEvent e) {
        dp.DWMouseMove(e.getX(), e.getY());
        this.repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        dp.paintPoint(g);
    }

    public void componentResized(ComponentEvent e)

    public void componentMoved(ComponentEvent e) {
    }

    public void componentShown(ComponentEvent e) {
    }

    public void componentHidden(ComponentEvent e) {
        timer.stop();
    }
}


package wprover;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.net.URL;

class JExPanel extends JPanel implements ActionListener, MouseListener, MouseMotionListener, ComponentListener {

    drawProcess dp;

    static ImageIcon icoa;

    static ImageIcon icos;

    JToggleButton button;

    Timer timer = null;

    public void paint(Graphics g) {
        super.paint(g);
        if (dp != null)
            dp.paintPoint(g);
    }

    public JExPanel() {
        super();
        this.setLayout(null);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.addComponentListener(this);
        this.setBackground(new Color(228, 236, 252));
        URL imageURL = GExpert.class.getResource("images/animate_start.gif");
        ImageIcon image = new ImageIcon(imageURL);
        URL imageURL1 = GExpert.class.getResource("images/animate_stop.gif");
        ImageIcon image1 = new ImageIcon(imageURL1);
        button = new JToggleButton(image) {

            public Dimension getPreferredSize() {
                return new Dimension(30, 28);
            }
        };
        this.add(button);
        button.addActionListener(this);
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
        button.setSelectedIcon(image1);
    }

    public static void setAinimateIcon(ImageIcon ico1, ImageIcon ico2) {
        icoa = ico1;
        icos = ico2;
    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 400);
    }

    public void setdrawP(drawProcess dp) {
        this.dp = dp;
        if (timer != null)
            timer.stop();
        if (dp.animate != null) {
            AnimateC ant = dp.animate;
            if (timer == null)
                timer = new Timer(ant.getInitValue(), this);
            else
                timer.setDelay(ant.getInitValue());
            timer.start();
            button.setIcon(icos);
            button.setVisible(true);
        } else
            button.setVisible(false);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button) {
            if (!timer.isRunning()) {
                dp.animationStart();
                button.setIcon(icos);
                timer.start();
            } else {
                dp.animationStop();
                button.setIcon(icoa);
                timer.stop();
            }
        } else if (e.getSource() == timer) {
            dp.animationOntime();
            this.repaint();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() > 1)
            dp.DWMouseDbClick(e.getX(), e.getY());
        if (e.getButton() == MouseEvent.BUTTON3)
            dp.DWMouseRightClick(e.getX(), e.getY());
    }

    public void mousePressed(MouseEvent e) {
        dp.DWButtonDown(e.getX(), e.getY());
        repaint();
    }

    public void mouseReleased(MouseEvent e) {

        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        dp.DWMouseDrag(e.getX(), e.getY());
        this.repaint();
    }

    public void mouseMoved(MouseEvent e) {
        dp.DWMouseMove(e.getX(), e.getY());
        this.repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        dp.paintPoint(g);
    }

    public void componentResized(ComponentEvent e) {
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
    }

    public void componentMoved(ComponentEvent e) {
    }

    public void componentShown(ComponentEvent e) {
    }

    public void componentHidden(ComponentEvent e) {
        timer.stop();
    }
}


if (dp.animate != null) {
            AnimateC ant = dp.animate;
            if (timer == null)
                timer = new Timer(ant.getInitValue(), this);
            else
                timer.setDelay(ant.getInitValue());
            timer.start();
            button.setIcon(icos);
            button.setVisible(true);
        } else
            button.setVisible(false);

package wprover;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.net.URL;

class JExPanel extends JPanel implements ActionListener, MouseListener, MouseMotionListener, ComponentListener {

    drawProcess dp;

    static ImageIcon icoa;

    static ImageIcon icos;

    JToggleButton button;

    Timer timer = null;

    public void paint(Graphics g) {
        super.paint(g);
        if (dp != null)
            dp.paintPoint(g);
    }

    public JExPanel() {
        super();
        this.setLayout(null);
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.addComponentListener(this);
        this.setBackground(new Color(228, 236, 252));
        URL imageURL = GExpert.class.getResource("images/animate_start.gif");
        ImageIcon image = new ImageIcon(imageURL);
        URL imageURL1 = GExpert.class.getResource("images/animate_stop.gif");
        ImageIcon image1 = new ImageIcon(imageURL1);
        button = new JToggleButton(image) {

            public Dimension getPreferredSize() {
                return new Dimension(30, 28);
            }
        };
        this.add(button);
        button.addActionListener(this);
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
        button.setSelectedIcon(image1);
    }

    public static void setAinimateIcon(ImageIcon ico1, ImageIcon ico2) {
        icoa = ico1;
        icos = ico2;
    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 400);
    }

    public void setdrawP(drawProcess dp) {
        this.dp = dp;
        if (timer != null)
            timer.stop();

    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == button) {
            if (!timer.isRunning()) {
                dp.animationStart();
                button.setIcon(icos);
                timer.start();
            } else {
                dp.animationStop();
                button.setIcon(icoa);
                timer.stop();
            }
        } else if (e.getSource() == timer) {
            dp.animationOntime();
            this.repaint();
        }
    }

    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() > 1)
            dp.DWMouseDbClick(e.getX(), e.getY());
        if (e.getButton() == MouseEvent.BUTTON3)
            dp.DWMouseRightClick(e.getX(), e.getY());
    }

    public void mousePressed(MouseEvent e) {
        dp.DWButtonDown(e.getX(), e.getY());
        repaint();
    }

    public void mouseReleased(MouseEvent e) {
        dp.DWButtonUp(e.getX(), e.getY());
        repaint();
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        dp.DWMouseDrag(e.getX(), e.getY());
        this.repaint();
    }

    public void mouseMoved(MouseEvent e) {
        dp.DWMouseMove(e.getX(), e.getY());
        this.repaint();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        dp.paintPoint(g);
    }

    public void componentResized(ComponentEvent e) {
        Dimension dm = this.getSize();
        button.setBounds(new Rectangle(0, (int) dm.getHeight() - 28, 32, 28));
    }

    public void componentMoved(ComponentEvent e) {
    }

    public void componentShown(ComponentEvent e) {
    }

    public void componentHidden(ComponentEvent e) {
        timer.stop();
    }
}


public ComponentLauncherInfo get(Pair<String, String> name)

package com.ra4king.circuitsim.gui;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import com.ra4king.circuitsim.gui.peers.arithmetic.AdderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.BitExtenderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ComparatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.DividerPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.MultiplierPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.NegatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.RandomGeneratorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ShifterPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.SubtractorPeer;
import com.ra4king.circuitsim.gui.peers.gates.AndGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.ControlledBufferPeer;
import com.ra4king.circuitsim.gui.peers.gates.NandGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NotGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.OrGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XnorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XorGatePeer;
import com.ra4king.circuitsim.gui.peers.io.Button;
import com.ra4king.circuitsim.gui.peers.io.HexDisplay;
import com.ra4king.circuitsim.gui.peers.io.LED;
import com.ra4king.circuitsim.gui.peers.io.LEDMatrix;
import com.ra4king.circuitsim.gui.peers.memory.DFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.memory.RAMPeer;
import com.ra4king.circuitsim.gui.peers.memory.ROMPeer;
import com.ra4king.circuitsim.gui.peers.memory.RegisterPeer;
import com.ra4king.circuitsim.gui.peers.memory.SRFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.misc.Text;
import com.ra4king.circuitsim.gui.peers.plexers.DecoderPeer;
import com.ra4king.circuitsim.gui.peers.plexers.DemultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.MultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.PriorityEncoderPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ClockPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ConstantPeer;
import com.ra4king.circuitsim.gui.peers.wiring.PinPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Probe;
import com.ra4king.circuitsim.gui.peers.wiring.SplitterPeer;
import com.ra4king.circuitsim.gui.peers.wiring.TransistorPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Tunnel;
import com.ra4king.circuitsim.simulator.SimulationException;
import javafx.scene.image.Image;
import javafx.util.Pair;

/**
 * @author Roi Atalla
 */
public class ComponentManager {

    private List<ComponentLauncherInfo> components;

    public static class ComponentLauncherInfo {

        public final Class<? extends ComponentPeer<?>> clazz;

        public final Pair<String, String> name;

        public final Image image;

        public final Properties properties;

        public final ComponentCreator<?> creator;

        ComponentLauncherInfo(Class<? extends ComponentPeer<?>> clazz, Pair<String, String> name, Image image, Properties properties, ComponentCreator<?> creator) {
            this.clazz = clazz;
            this.name = name;
            this.image = image;
            this.properties = properties;
            this.creator = creator;
        }

        @Override
        public int hashCode() {
            return clazz.hashCode() ^ name.hashCode() ^ (image == null ? 0 : image.hashCode()) ^ properties.hashCode() ^ creator.hashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof ComponentLauncherInfo)) {
                return false;
            }
            ComponentLauncherInfo info = (ComponentLauncherInfo) other;
            return info.clazz == this.clazz && info.name.equals(this.name);
        }
    }

    public interface ComponentManagerInterface {

        void addComponent(Pair<String, String> name, Image image, Properties defaultProperties);
    }

    static <T extends ComponentPeer<?>> ComponentCreator<T> forClass(Class<T> clazz) {
        return (properties, x, y) -> {
            try {
                return clazz.getConstructor(Properties.class, Integer.TYPE, Integer.TYPE).newInstance(properties, x, y);
            } catch (NoSuchMethodException exc) {
                throw new RuntimeException("Must have constructor taking (Properties props, int x, int y)");
            } catch (InvocationTargetException exc) {
                if (exc.getTargetException() instanceof SimulationException) {
                    throw (SimulationException) exc.getTargetException();
                }
                throw new RuntimeException(exc.getTargetException());
            } catch (RuntimeException exc) {
                throw exc;
            } catch (Exception exc) {
                throw new RuntimeException(exc);
            }
        };
    }

    ComponentManager() {
        components = new ArrayList<>();
        registerDefaultComponents();
    }

{
        for (ComponentLauncherInfo component : components) {
            if (component.name.equals(name)) {
                return component;
            }
        }
        throw new IllegalArgumentException("Component not registered: " + name);
    }

    // To be able to use getClass(), ComponentPeer cannot be parameterized.
    @SuppressWarnings("rawtypes")
    public ComponentLauncherInfo get(Class<? extends ComponentPeer> clazz, Properties properties) throws SimulationException {
        ComponentLauncherInfo firstComponent = null;
        for (ComponentLauncherInfo component : components) {
            if (component.clazz == clazz) {
                firstComponent = component;
                if (properties.intersect(component.properties).equals(component.properties)) {
                    return component;
                }
            }
        }
        if (firstComponent != null) {
            return firstComponent;
        }
        throw new SimulationException("Component not registered: " + clazz);
    }

    public void forEach(Consumer<ComponentLauncherInfo> consumer) {
        components.forEach(consumer);
    }

    public <T extends ComponentPeer<?>> void register(Class<T> clazz) {
        try {
            ComponentCreator<?> creator = forClass(clazz);
            Method method = clazz.getMethod("installComponent", ComponentManagerInterface.class);
            method.invoke(null, (ComponentManagerInterface) (name, image, defaultProperties) -> {
                if (name == null || defaultProperties == null) {
                    throw new NullPointerException("Name and Properties cannot be null.");
                }
                ComponentLauncherInfo info = new ComponentLauncherInfo(clazz, name, image, defaultProperties, creator);
                if (!components.contains(info)) {
                    components.add(info);
                }
            });
        } catch (NoSuchMethodException exc) {
            throw new RuntimeException("Must implement: public static void installComponent" + "(ComponentManagerInterface): " + clazz);
        } catch (RuntimeException exc) {
            throw exc;
        } catch (Exception exc) {
            throw new RuntimeException(exc);
        }
    }

    private void registerDefaultComponents() {
        register(PinPeer.class);
        register(ConstantPeer.class);
        register(Probe.class);
        register(ClockPeer.class);
        register(SplitterPeer.class);
        register(Tunnel.class);
        register(TransistorPeer.class);
        register(AndGatePeer.class);
        register(NandGatePeer.class);
        register(OrGatePeer.class);
        register(NorGatePeer.class);
        register(XorGatePeer.class);
        register(XnorGatePeer.class);
        register(NotGatePeer.class);
        register(ControlledBufferPeer.class);
        register(MultiplexerPeer.class);
        register(DemultiplexerPeer.class);
        register(DecoderPeer.class);
        register(PriorityEncoderPeer.class);
        register(RegisterPeer.class);
        register(SRFlipFlopPeer.class);
        register(DFlipFlopPeer.class);
        register(RAMPeer.class);
        register(ROMPeer.class);
        register(AdderPeer.class);
        register(SubtractorPeer.class);
        register(MultiplierPeer.class);
        register(DividerPeer.class);
        register(NegatorPeer.class);
        register(ComparatorPeer.class);
        register(BitExtenderPeer.class);
        register(ShifterPeer.class);
        register(RandomGeneratorPeer.class);
        register(Button.class);
        register(LED.class);
        register(LEDMatrix.class);
        register(HexDisplay.class);
        register(Text.class);
    }

    public interface ComponentCreator<T extends ComponentPeer<?>> {

        T createComponent(Properties properties, int x, int y);
    }
}


{
        for (ComponentLauncherInfo component : components) {
            if (component.name.equals(name)) {
                return component;
            }
        }
        throw new IllegalArgumentException("Component not registered: " + name);
    }

package com.ra4king.circuitsim.gui;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import com.ra4king.circuitsim.gui.peers.arithmetic.AdderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.BitExtenderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ComparatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.DividerPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.MultiplierPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.NegatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.RandomGeneratorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ShifterPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.SubtractorPeer;
import com.ra4king.circuitsim.gui.peers.gates.AndGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.ControlledBufferPeer;
import com.ra4king.circuitsim.gui.peers.gates.NandGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NotGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.OrGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XnorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XorGatePeer;
import com.ra4king.circuitsim.gui.peers.io.Button;
import com.ra4king.circuitsim.gui.peers.io.HexDisplay;
import com.ra4king.circuitsim.gui.peers.io.LED;
import com.ra4king.circuitsim.gui.peers.io.LEDMatrix;
import com.ra4king.circuitsim.gui.peers.memory.DFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.memory.RAMPeer;
import com.ra4king.circuitsim.gui.peers.memory.ROMPeer;
import com.ra4king.circuitsim.gui.peers.memory.RegisterPeer;
import com.ra4king.circuitsim.gui.peers.memory.SRFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.misc.Text;
import com.ra4king.circuitsim.gui.peers.plexers.DecoderPeer;
import com.ra4king.circuitsim.gui.peers.plexers.DemultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.MultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.PriorityEncoderPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ClockPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ConstantPeer;
import com.ra4king.circuitsim.gui.peers.wiring.PinPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Probe;
import com.ra4king.circuitsim.gui.peers.wiring.SplitterPeer;
import com.ra4king.circuitsim.gui.peers.wiring.TransistorPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Tunnel;
import com.ra4king.circuitsim.simulator.SimulationException;
import javafx.scene.image.Image;
import javafx.util.Pair;

/**
 * @author Roi Atalla
 */
public class ComponentManager {

    private List<ComponentLauncherInfo> components;

    public static class ComponentLauncherInfo {

        public final Class<? extends ComponentPeer<?>> clazz;

        public final Pair<String, String> name;

        public final Image image;

        public final Properties properties;

        public final ComponentCreator<?> creator;

        ComponentLauncherInfo(Class<? extends ComponentPeer<?>> clazz, Pair<String, String> name, Image image, Properties properties, ComponentCreator<?> creator) {
            this.clazz = clazz;
            this.name = name;
            this.image = image;
            this.properties = properties;
            this.creator = creator;
        }

        @Override
        public int hashCode() {
            return clazz.hashCode() ^ name.hashCode() ^ (image == null ? 0 : image.hashCode()) ^ properties.hashCode() ^ creator.hashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof ComponentLauncherInfo)) {
                return false;
            }
            ComponentLauncherInfo info = (ComponentLauncherInfo) other;
            return info.clazz == this.clazz && info.name.equals(this.name);
        }
    }

    public interface ComponentManagerInterface {

        void addComponent(Pair<String, String> name, Image image, Properties defaultProperties);
    }

    static <T extends ComponentPeer<?>> ComponentCreator<T> forClass(Class<T> clazz) {
        return (properties, x, y) -> {
            try {
                return clazz.getConstructor(Properties.class, Integer.TYPE, Integer.TYPE).newInstance(properties, x, y);
            } catch (NoSuchMethodException exc) {
                throw new RuntimeException("Must have constructor taking (Properties props, int x, int y)");
            } catch (InvocationTargetException exc) {
                if (exc.getTargetException() instanceof SimulationException) {
                    throw (SimulationException) exc.getTargetException();
                }
                throw new RuntimeException(exc.getTargetException());
            } catch (RuntimeException exc) {
                throw exc;
            } catch (Exception exc) {
                throw new RuntimeException(exc);
            }
        };
    }

    ComponentManager() {
        components = new ArrayList<>();
        registerDefaultComponents();
    }

    public ComponentLauncherInfo get(Pair<String, String> name)

    // To be able to use getClass(), ComponentPeer cannot be parameterized.
    @SuppressWarnings("rawtypes")
    public ComponentLauncherInfo get(Class<? extends ComponentPeer> clazz, Properties properties) throws SimulationException {
        ComponentLauncherInfo firstComponent = null;
        for (ComponentLauncherInfo component : components) {
            if (component.clazz == clazz) {
                firstComponent = component;
                if (properties.intersect(component.properties).equals(component.properties)) {
                    return component;
                }
            }
        }
        if (firstComponent != null) {
            return firstComponent;
        }
        throw new SimulationException("Component not registered: " + clazz);
    }

    public void forEach(Consumer<ComponentLauncherInfo> consumer) {
        components.forEach(consumer);
    }

    public <T extends ComponentPeer<?>> void register(Class<T> clazz) {
        try {
            ComponentCreator<?> creator = forClass(clazz);
            Method method = clazz.getMethod("installComponent", ComponentManagerInterface.class);
            method.invoke(null, (ComponentManagerInterface) (name, image, defaultProperties) -> {
                if (name == null || defaultProperties == null) {
                    throw new NullPointerException("Name and Properties cannot be null.");
                }
                ComponentLauncherInfo info = new ComponentLauncherInfo(clazz, name, image, defaultProperties, creator);
                if (!components.contains(info)) {
                    components.add(info);
                }
            });
        } catch (NoSuchMethodException exc) {
            throw new RuntimeException("Must implement: public static void installComponent" + "(ComponentManagerInterface): " + clazz);
        } catch (RuntimeException exc) {
            throw exc;
        } catch (Exception exc) {
            throw new RuntimeException(exc);
        }
    }

    private void registerDefaultComponents() {
        register(PinPeer.class);
        register(ConstantPeer.class);
        register(Probe.class);
        register(ClockPeer.class);
        register(SplitterPeer.class);
        register(Tunnel.class);
        register(TransistorPeer.class);
        register(AndGatePeer.class);
        register(NandGatePeer.class);
        register(OrGatePeer.class);
        register(NorGatePeer.class);
        register(XorGatePeer.class);
        register(XnorGatePeer.class);
        register(NotGatePeer.class);
        register(ControlledBufferPeer.class);
        register(MultiplexerPeer.class);
        register(DemultiplexerPeer.class);
        register(DecoderPeer.class);
        register(PriorityEncoderPeer.class);
        register(RegisterPeer.class);
        register(SRFlipFlopPeer.class);
        register(DFlipFlopPeer.class);
        register(RAMPeer.class);
        register(ROMPeer.class);
        register(AdderPeer.class);
        register(SubtractorPeer.class);
        register(MultiplierPeer.class);
        register(DividerPeer.class);
        register(NegatorPeer.class);
        register(ComparatorPeer.class);
        register(BitExtenderPeer.class);
        register(ShifterPeer.class);
        register(RandomGeneratorPeer.class);
        register(Button.class);
        register(LED.class);
        register(LEDMatrix.class);
        register(HexDisplay.class);
        register(Text.class);
    }

    public interface ComponentCreator<T extends ComponentPeer<?>> {

        T createComponent(Properties properties, int x, int y);
    }
}


package com.ra4king.circuitsim.gui;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import com.ra4king.circuitsim.gui.peers.arithmetic.AdderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.BitExtenderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ComparatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.DividerPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.MultiplierPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.NegatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.RandomGeneratorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ShifterPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.SubtractorPeer;
import com.ra4king.circuitsim.gui.peers.gates.AndGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.ControlledBufferPeer;
import com.ra4king.circuitsim.gui.peers.gates.NandGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NotGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.OrGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XnorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XorGatePeer;
import com.ra4king.circuitsim.gui.peers.io.Button;
import com.ra4king.circuitsim.gui.peers.io.HexDisplay;
import com.ra4king.circuitsim.gui.peers.io.LED;
import com.ra4king.circuitsim.gui.peers.io.LEDMatrix;
import com.ra4king.circuitsim.gui.peers.memory.DFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.memory.RAMPeer;
import com.ra4king.circuitsim.gui.peers.memory.ROMPeer;
import com.ra4king.circuitsim.gui.peers.memory.RegisterPeer;
import com.ra4king.circuitsim.gui.peers.memory.SRFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.misc.Text;
import com.ra4king.circuitsim.gui.peers.plexers.DecoderPeer;
import com.ra4king.circuitsim.gui.peers.plexers.DemultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.MultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.PriorityEncoderPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ClockPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ConstantPeer;
import com.ra4king.circuitsim.gui.peers.wiring.PinPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Probe;
import com.ra4king.circuitsim.gui.peers.wiring.SplitterPeer;
import com.ra4king.circuitsim.gui.peers.wiring.TransistorPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Tunnel;
import com.ra4king.circuitsim.simulator.SimulationException;
import javafx.scene.image.Image;
import javafx.util.Pair;

/**
 * @author Roi Atalla
 */
public class ComponentManager {

    private List<ComponentLauncherInfo> components;

    public static class ComponentLauncherInfo {

        public final Class<? extends ComponentPeer<?>> clazz;

        public final Pair<String, String> name;

        public final Image image;

        public final Properties properties;

        public final ComponentCreator<?> creator;

        ComponentLauncherInfo(Class<? extends ComponentPeer<?>> clazz, Pair<String, String> name, Image image, Properties properties, ComponentCreator<?> creator) {
            this.clazz = clazz;
            this.name = name;
            this.image = image;
            this.properties = properties;
            this.creator = creator;
        }

        @Override
        public int hashCode() {
            return clazz.hashCode() ^ name.hashCode() ^ (image == null ? 0 : image.hashCode()) ^ properties.hashCode() ^ creator.hashCode();
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof ComponentLauncherInfo)) {
                return false;
            }
            ComponentLauncherInfo info = (ComponentLauncherInfo) other;
            return info.clazz == this.clazz && info.name.equals(this.name);
        }
    }

    public interface ComponentManagerInterface {

        void addComponent(Pair<String, String> name, Image image, Properties defaultProperties);
    }

    static <T extends ComponentPeer<?>> ComponentCreator<T> forClass(Class<T> clazz) {
        return (properties, x, y) -> {
            try {
                return clazz.getConstructor(Properties.class, Integer.TYPE, Integer.TYPE).newInstance(properties, x, y);
            } catch (NoSuchMethodException exc) {
                throw new RuntimeException("Must have constructor taking (Properties props, int x, int y)");
            } catch (InvocationTargetException exc) {
                if (exc.getTargetException() instanceof SimulationException) {
                    throw (SimulationException) exc.getTargetException();
                }
                throw new RuntimeException(exc.getTargetException());
            } catch (RuntimeException exc) {
                throw exc;
            } catch (Exception exc) {
                throw new RuntimeException(exc);
            }
        };
    }

    ComponentManager() {
        components = new ArrayList<>();
        registerDefaultComponents();
    }

    public ComponentLauncherInfo get(Pair<String, String> name) {
        for (ComponentLauncherInfo component : components) {
            if (component.name.equals(name)) {
                return component;
            }
        }
        throw new IllegalArgumentException("Component not registered: " + name);
    }

    // To be able to use getClass(), ComponentPeer cannot be parameterized.
    @SuppressWarnings("rawtypes")
    public ComponentLauncherInfo get(Class<? extends ComponentPeer> clazz, Properties properties) throws SimulationException {
        ComponentLauncherInfo firstComponent = null;
        for (ComponentLauncherInfo component : components) {
            if (component.clazz == clazz) {
                firstComponent = component;
                if (properties.intersect(component.properties).equals(component.properties)) {
                    return component;
                }
            }
        }
        if (firstComponent != null) {
            return firstComponent;
        }
        throw new SimulationException("Component not registered: " + clazz);
    }

    public void forEach(Consumer<ComponentLauncherInfo> consumer) {
        components.forEach(consumer);
    }

    public <T extends ComponentPeer<?>> void register(Class<T> clazz) {
        try {
            ComponentCreator<?> creator = forClass(clazz);
            Method method = clazz.getMethod("installComponent", ComponentManagerInterface.class);
            method.invoke(null, (ComponentManagerInterface) (name, image, defaultProperties) -> {
                if (name == null || defaultProperties == null) {
                    throw new NullPointerException("Name and Properties cannot be null.");
                }
                ComponentLauncherInfo info = new ComponentLauncherInfo(clazz, name, image, defaultProperties, creator);
                if (!components.contains(info)) {
                    components.add(info);
                }
            });
        } catch (NoSuchMethodException exc) {
            throw new RuntimeException("Must implement: public static void installComponent" + "(ComponentManagerInterface): " + clazz);
        } catch (RuntimeException exc) {
            throw exc;
        } catch (Exception exc) {
            throw new RuntimeException(exc);
        }
    }

    private void registerDefaultComponents() {
        register(PinPeer.class);
        register(ConstantPeer.class);
        register(Probe.class);
        register(ClockPeer.class);
        register(SplitterPeer.class);
        register(Tunnel.class);
        register(TransistorPeer.class);
        register(AndGatePeer.class);
        register(NandGatePeer.class);
        register(OrGatePeer.class);
        register(NorGatePeer.class);
        register(XorGatePeer.class);
        register(XnorGatePeer.class);
        register(NotGatePeer.class);
        register(ControlledBufferPeer.class);
        register(MultiplexerPeer.class);
        register(Demulti

        register(DecoderPeer.class);
        register(PriorityEncoderPeer.class);
        register(RegisterPeer.class);
        register(SRFlipFlopPeer.class);
        register(DFlipFlopPeer.class);
        register(RAMPeer.class);
        register(ROMPeer.class);
        register(AdderPeer.class);
        register(SubtractorPeer.class);
        register(MultiplierPeer.class);
        register(DividerPeer.class);
        register(NegatorPeer.class);
        register(ComparatorPeer.class);
        register(BitExtenderPeer.class);
        register(ShifterPeer.class);
        register(RandomGeneratorPeer.class);
        register(Button.class);
        register(LED.class);
        register(LEDMatrix.class);
        register(HexDisplay.class);
        register(Text.class);
    }

    public interface ComponentCreator<T extends ComponentPeer<?>> {

        T createComponent(Properties properties, int x, int y);
    }
}


if (!(other instanceof ComponentLauncherInfo)) {
                return false;
            }

package com.ra4king.circuitsim.gui;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import com.ra4king.circuitsim.gui.peers.arithmetic.AdderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.BitExtenderPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ComparatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.DividerPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.MultiplierPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.NegatorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.RandomGeneratorPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.ShifterPeer;
import com.ra4king.circuitsim.gui.peers.arithmetic.SubtractorPeer;
import com.ra4king.circuitsim.gui.peers.gates.AndGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.ControlledBufferPeer;
import com.ra4king.circuitsim.gui.peers.gates.NandGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.NotGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.OrGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XnorGatePeer;
import com.ra4king.circuitsim.gui.peers.gates.XorGatePeer;
import com.ra4king.circuitsim.gui.peers.io.Button;
import com.ra4king.circuitsim.gui.peers.io.HexDisplay;
import com.ra4king.circuitsim.gui.peers.io.LED;
import com.ra4king.circuitsim.gui.peers.io.LEDMatrix;
import com.ra4king.circuitsim.gui.peers.memory.DFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.memory.RAMPeer;
import com.ra4king.circuitsim.gui.peers.memory.ROMPeer;
import com.ra4king.circuitsim.gui.peers.memory.RegisterPeer;
import com.ra4king.circuitsim.gui.peers.memory.SRFlipFlopPeer;
import com.ra4king.circuitsim.gui.peers.misc.Text;
import com.ra4king.circuitsim.gui.peers.plexers.DecoderPeer;
import com.ra4king.circuitsim.gui.peers.plexers.DemultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.MultiplexerPeer;
import com.ra4king.circuitsim.gui.peers.plexers.PriorityEncoderPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ClockPeer;
import com.ra4king.circuitsim.gui.peers.wiring.ConstantPeer;
import com.ra4king.circuitsim.gui.peers.wiring.PinPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Probe;
import com.ra4king.circuitsim.gui.peers.wiring.SplitterPeer;
import com.ra4king.circuitsim.gui.peers.wiring.TransistorPeer;
import com.ra4king.circuitsim.gui.peers.wiring.Tunnel;
import com.ra4king.circuitsim.simulator.SimulationException;
import javafx.scene.image.Image;
import javafx.util.Pair;

/**
 * @author Roi Atalla
 */
public class ComponentManager {

    private List<ComponentLauncherInfo> components;

    public static class ComponentLauncherInfo {

        public final Class<? extends ComponentPeer<?>> clazz;

        public final Pair<String, String> name;

        public final Image image;

        public final Properties properties;

        public final ComponentCreator<?> creator;

        ComponentLauncherInfo(Class<? extends ComponentPeer<?>> clazz, Pair<String, String> name, Image image, Properties properties, ComponentCreator<?> creator) {
            this.clazz = clazz;
            this.name = name;
            this.image = image;
            this.properties = properties;
            this.creator = creator;
        }

        @Override
        public int hashCode() {
            return clazz.hashCode() ^ name.hashCode() ^ (image == null ? 0 : image.hashCode()) ^ properties.hashCode() ^ creator.hashCode();
        }

        @Override
        public boolean equals(Object other) {

            ComponentLauncherInfo info = (ComponentLauncherInfo) other;
            return info.clazz == this.clazz && info.name.equals(this.name);
        }
    }

    public interface ComponentManagerInterface {

        void addComponent(Pair<String, String> name, Image image, Properties defaultProperties);
    }

    static <T extends ComponentPeer<?>> ComponentCreator<T> forClass(Class<T> clazz) {
        return (properties, x, y) -> {
            try {
                return clazz.getConstructor(Properties.class, Integer.TYPE, Integer.TYPE).newInstance(properties, x, y);
            } catch (NoSuchMethodException exc) {
                throw new RuntimeException("Must have constructor taking (Properties props, int x, int y)");
            } catch (InvocationTargetException exc) {
                if (exc.getTargetException() instanceof SimulationException) {
                    throw (SimulationException) exc.getTargetException();
                }
                throw new RuntimeException(exc.getTargetException());
            } catch (RuntimeException exc) {
                throw exc;
            } catch (Exception exc) {
                throw new RuntimeException(exc);
            }
        };
    }

    ComponentManager() {
        components = new ArrayList<>();
        registerDefaultComponents();
    }

    public ComponentLauncherInfo get(Pair<String, String> name) {
        for (ComponentLauncherInfo component : components) {
            if (component.name.equals(name)) {
                return component;
            }
        }
        throw new IllegalArgumentException("Component not registered: " + name);
    }

    // To be able to use getClass(), ComponentPeer cannot be parameterized.
    @SuppressWarnings("rawtypes")
    public ComponentLauncherInfo get(Class<? extends ComponentPeer> clazz, Properties properties) throws SimulationException {
        ComponentLauncherInfo firstComponent = null;
        for (ComponentLauncherInfo component : components) {
            if (component.clazz == clazz) {
                firstComponent = component;
                if (properties.intersect(component.properties).equals(component.properties)) {
                    return component;
                }
            }
        }
        if (firstComponent != null) {
            return firstComponent;
        }
        throw new SimulationException("Component not registered: " + clazz);
    }

    public void forEach(Consumer<ComponentLauncherInfo> consumer) {
        components.forEach(consumer);
    }

    public <T extends ComponentPeer<?>> void register(Class<T> clazz) {
        try {
            ComponentCreator<?> creator = forClass(clazz);
            Method method = clazz.getMethod("installComponent", ComponentManagerInterface.class);
            method.invoke(null, (ComponentManagerInterface) (name, image, defaultProperties) -> {
                if (name == null || defaultProperties == null) {
                    throw new NullPointerException("Name and Properties cannot be null.");
                }
                ComponentLauncherInfo info = new ComponentLauncherInfo(clazz, name, image, defaultProperties, creator);
                if (!components.contains(info)) {
                    components.add(info);
                }
            });
        } catch (NoSuchMethodException exc) {
            throw new RuntimeException("Must implement: public static void installComponent" + "(ComponentManagerInterface): " + clazz);
        } catch (RuntimeException exc) {
            throw exc;
        } catch (Exception exc) {
            throw new RuntimeException(exc);
        }
    }

    private void registerDefaultComponents() {
        register(PinPeer.class);
        register(ConstantPeer.class);
        register(Probe.class);
        register(ClockPeer.class);
        register(SplitterPeer.class);
        register(Tunnel.class);
        register(TransistorPeer.class);
        register(AndGatePeer.class);
        register(NandGatePeer.class);
        register(OrGatePeer.class);
        register(NorGatePeer.class);
        register(XorGatePeer.class);
        register(XnorGatePeer.class);
        register(NotGatePeer.class);
        register(ControlledBufferPeer.class);
        register(MultiplexerPeer.class);
        register(DemultiplexerPeer.class);
        register(DecoderPeer.class);
        register(PriorityEncoderPeer.class);
        register(RegisterPeer.class);
        register(SRFlipFlopPeer.class);
        register(DFlipFlopPeer.class);
        register(RAMPeer.class);
        register(ROMPeer.class);
        register(AdderPeer.class);
        register(SubtractorPeer.class);
        register(MultiplierPeer.class);
        register(DividerPeer.class);
        register(NegatorPeer.class);
        register(ComparatorPeer.class);
        register(BitExtenderPeer.class);
        register(ShifterPeer.class);
        register(RandomGeneratorPeer.class);
        register(Button.class);
        register(LED.class);
        register(LEDMatrix.class);
        register(HexDisplay.class);
        register(Text.class);
    }

    public interface ComponentCreator<T extends ComponentPeer<?>> {

        T createComponent(Properties properties, int x, int y);
    }
}


package org.sdnplatform.sync.internal.version;

import java.util.List;
import java.util.ListIterator;
import org.sdnplatform.sync.IInconsistencyResolver;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.IVersion.Occurred;
import com.google.common.collect.Lists;

/**
 * An inconsistency resolver that uses the object VectorClocks leaving only a
 * set of concurrent versions remaining.
 */
public class VectorClockInconsistencyResolver<T> implements IInconsistencyResolver<Versioned<T>> {

    public List<Versioned<T>> resolveConflicts(List<Versioned<T>> items) {
        int size = items.size();
        if (size <= 1)
            return items;
        List<Versioned<T>> newItems = Lists.newArrayList();
        for (Versioned<T> v1 : items) {
            boolean found = false;
            for (ListIterator<Versioned<T>> it2 = newItems.listIterator(); it2.hasNext(); ) {
                Versioned<T> v2 = it2.next();
                Occurred compare = v1.getVersion().compare(v2.getVersion());
                if (compare == Occurred.AFTER) {
                    if (found)
                        it2.remove();
                    else
                        it2.set(v1);
                }
                if (compare != Occurred.CONCURRENTLY)
                    found = true;
            }
            if (!found)
                newItems.add(v1);
        }
        return newItems;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        return (o != null && getClass() == o.getClass());
    }

{
        return getClass().hashCode();
    }
}


{
        return getClass().hashCode();
    }

package org.sdnplatform.sync.internal.version;

import java.util.List;
import java.util.ListIterator;
import org.sdnplatform.sync.IInconsistencyResolver;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.IVersion.Occurred;
import com.google.common.collect.Lists;

/**
 * An inconsistency resolver that uses the object VectorClocks leaving only a
 * set of concurrent versions remaining.
 */
public class VectorClockInconsistencyResolver<T> implements IInconsistencyResolver<Versioned<T>> {

    public List<Versioned<T>> resolveConflicts(List<Versioned<T>> items) {
        int size = items.size();
        if (size <= 1)
            return items;
        List<Versioned<T>> newItems = Lists.newArrayList();
        for (Versioned<T> v1 : items) {
            boolean found = false;
            for (ListIterator<Versioned<T>> it2 = newItems.listIterator(); it2.hasNext(); ) {
                Versioned<T> v2 = it2.next();
                Occurred compare = v1.getVersion().compare(v2.getVersion());
                if (compare == Occurred.AFTER) {
                    if (found)
                        it2.remove();
                    else
                        it2.set(v1);
                }
                if (compare != Occurred.CONCURRENTLY)
                    found = true;
            }
            if (!found)
                newItems.add(v1);
        }
        return newItems;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        return (o != null && getClass() == o.getClass());
    }

    @Override
    public int hashCode()


package org.sdnplatform.sync.internal.version;

import java.util.List;
import java.util.ListIterator;
import org.sdnplatform.sync.IInconsistencyResolver;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.IVersion.Occurred;
import com.google.common.collect.Lists;

/**
 * An inconsistency resolver that uses the object VectorClocks leaving only a
 * set of concurrent versions remaining.
 */
public class VectorClockInconsistencyResolver<T> implements IInconsistencyResolver<Versioned<T>> {

    public List<Versioned<T>> resolveConflicts(List<Versioned<T>> items) {
        int size = items.size();
        if (size <= 1)
            return items;
        List<Versioned<T>> newItems = Lists.newArrayList();
        for (Versioned<T> v1 : items) {
            boolean found = false;
            for (ListIterator<Versioned<T>> it2 = newItems.listIterator(); it2.hasNext(); ) {
                Versioned<T> v2 = it2.next();
                Occurred compare = v1.getVersion().compare(v2.getVersion());
                if (compare == Occurred.AFTER) {
                    if (found)
                        it2.remove();
                    else
                        it2.set(v1);
                }
                if (compare != Occurred.CONCURRENTLY)
                    found = true;
            }
            if (!found)
                newItems.add(v1);
        }
        return newItems;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        return (o != null && getClass() == o.get

    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
}


if (found)
                        it2.remove();
                    else
                        it2.set(v1);

package org.sdnplatform.sync.internal.version;

import java.util.List;
import java.util.ListIterator;
import org.sdnplatform.sync.IInconsistencyResolver;
import org.sdnplatform.sync.Versioned;
import org.sdnplatform.sync.IVersion.Occurred;
import com.google.common.collect.Lists;

/**
 * An inconsistency resolver that uses the object VectorClocks leaving only a
 * set of concurrent versions remaining.
 */
public class VectorClockInconsistencyResolver<T> implements IInconsistencyResolver<Versioned<T>> {

    public List<Versioned<T>> resolveConflicts(List<Versioned<T>> items) {
        int size = items.size();
        if (size <= 1)
            return items;
        List<Versioned<T>> newItems = Lists.newArrayList();
        for (Versioned<T> v1 : items) {
            boolean found = false;
            for (ListIterator<Versioned<T>> it2 = newItems.listIterator(); it2.hasNext(); ) {
                Versioned<T> v2 = it2.next();
                Occurred compare = v1.getVersion().compare(v2.getVersion());
                if (compare == Occurred.AFTER) {

                }
                if (compare != Occurred.CONCURRENTLY)
                    found = true;
            }
            if (!found)
                newItems.add(v1);
        }
        return newItems;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        return (o != null && getClass() == o.getClass());
    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
}


@HystrixCommand
    @GetMapping("/getProductInfoList")
    public String getProductInfoList(@RequestParam("number") Integer number)

package com.zxin.order.controller;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;

@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {

    // 超时配置

{
        if (number % 2 == 0) {
            return "success";
        }
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.postForObject("http://127.0.0.1:8005/product/listForOrder", Arrays.asList("157875196366160022"), String.class);
    }

    private String fallback() {
        return "太拥挤了, 请稍后再试~~";
    }

    private String defaultFallback() {
        return "默认提示：太拥挤了, 请稍后再试~~";
    }
}


package com.zxin.order.controller;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;

@RestController
@DefaultProperties(defaultFallback = "defaultFallback")
public class HystrixController {

    // 超时配置
    @HystrixCommand
    @GetMapping("/getProductInfoList")
    public String getProductInfoList(@RequestParam("number") Integer number) {
        if (number % 2 == 0) {
            return "success";
        }
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate.postForObject("http://127.0.0.1:8005/product/listForOrder", Arrays.asList("157875196366160022"), String.class);
    }

    private String fallback()

    private String defaultFallback() {
        return "默认提示：太拥挤了, 请稍后再试~~";
    }
}