try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException ex) {
                onWebsocketError(webSocketClient, ex);
            }

package org.java_websocket.client;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.URI;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.java_websocket.AbstractWebSocket;
import org.java_websocket.WebSocket;
import org.java_websocket.WebSocketImpl;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.enums.Opcode;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.exceptions.InvalidHandshakeException;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.framing.Framedata;
import org.java_websocket.handshake.HandshakeImpl1Client;
import org.java_websocket.handshake.Handshakedata;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.protocols.IProtocol;

/**
 * A subclass must implement at least <var>onOpen</var>, <var>onClose</var>, and
 * <var>onMessage</var> to be useful. At runtime the user is expected to establish a connection via
 * {@link #connect()}, then receive events like {@link #onMessage(String)} via the overloaded
 * methods and to {@link #send(String)} data to the server.
 */
public abstract class WebSocketClient extends AbstractWebSocket implements Runnable, WebSocket {

    /**
     * The URI this channel is supposed to connect to.
     */
    protected URI uri = null;

    /**
     * The underlying engine
     */
    private WebSocketImpl engine = null;

    private Socket socket = null;

    private SocketFactory socketFactory = null;

    /**
     * The used OutputStream
     */
    private OutputStream ostream;

    /**
     * The used proxy, if any
     */
    private Proxy proxy = Proxy.NO_PROXY;

    /**
     * The thread to write outgoing message
     */
    private Thread writeThread;

    /**
     * The thread to connect and read message
     */
    private Thread connectReadThread;

    /**
     * The draft to use
     */
    private Draft draft;

    /**
     * The additional headers to use
     */
    private Map<String, String> headers;

    private CountDownLatch connectLatch = new CountDownLatch(1);

    private CountDownLatch closeLatch = new CountDownLatch(1);

    /**
     * The socket timeout value to be used in milliseconds.
     */
    private int connectTimeout = 0;

    /**
     * DNS resolver that translates a URI to an InetAddress
     *
     * @see InetAddress
     * @since 1.4.1
     */
    private DnsResolver dnsResolver = null;

    /**
     * Constructs a WebSocketClient instance and sets it to the connect to the specified URI. The
     * channel does not attampt to connect automatically. The connection will be established once you
     * call <var>connect</var>.
     *
     * @param serverUri the server URI to connect to
     */
    public WebSocketClient(URI serverUri) {
        this(serverUri, new Draft_6455());
    }

    /**
     * Constructs a WebSocketClient instance and sets it to the connect to the specified URI. The
     * channel does not attampt to connect automatically. The connection will be established once you
     * call <var>connect</var>.
     *
     * @param serverUri     the server URI to connect to
     * @param protocolDraft The draft which should be used for this connection
     */
    public WebSocketClient(URI serverUri, Draft protocolDraft) {
        this(serverUri, protocolDraft, null, 0);
    }

    /**
     * Constructs a WebSocketClient instance and sets it to the connect to the specified URI. The
     * channel does not attampt to connect automatically. The connection will be established once you
     * call <var>connect</var>.
     *
     * @param serverUri   the server URI to connect to
     * @param httpHeaders Additional HTTP-Headers
     * @since 1.3.8
     */
    public WebSocketClient(URI serverUri, Map<String, String> httpHeaders) {
        this(serverUri, new Draft_6455(), httpHeaders);
    }

    /**
     * Constructs a WebSocketClient instance and sets it to the connect to the specified URI. The
     * channel does not attampt to connect automatically. The connection will be established once you
     * call <var>connect</var>.
     *
     * @param serverUri     the server URI to connect to
     * @param protocolDraft The draft which should be used for this connection
     * @param httpHeaders   Additional HTTP-Headers
     * @since 1.3.8
     */
    public WebSocketClient(URI serverUri, Draft protocolDraft, Map<String, String> httpHeaders) {
        this(serverUri, protocolDraft, httpHeaders, 0);
    }

    /**
     * Constructs a WebSocketClient instance and sets it to the connect to the specified URI. The
     * channel does not attampt to connect automatically. The connection will be established once you
     * call <var>connect</var>.
     *
     * @param serverUri      the server URI to connect to
     * @param protocolDraft  The draft which should be used for this connection
     * @param httpHeaders    Additional HTTP-Headers
     * @param connectTimeout The Timeout for the connection
     */
    public WebSocketClient(URI serverUri, Draft protocolDraft, Map<String, String> httpHeaders, int connectTimeout) {
        if (serverUri == null) {
            throw new IllegalArgumentException();
        } else if (protocolDraft == null) {
            throw new IllegalArgumentException("null as draft is permitted for `WebSocketServer` only!");
        }
        this.uri = serverUri;
        this.draft = protocolDraft;
        this.dnsResolver = new DnsResolver() {

            @Override
            public InetAddress resolve(URI uri) throws UnknownHostException {
                return InetAddress.getByName(uri.getHost());
            }
        };
        if (httpHeaders != null) {
            headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
            headers.putAll(httpHeaders);
        }
        this.connectTimeout = connectTimeout;
        setTcpNoDelay(false);
        setReuseAddr(false);
        this.engine = new WebSocketImpl(this, protocolDraft);
    }

    /**
     * Returns the URI that this WebSocketClient is connected to.
     *
     * @return the URI connected to
     */
    public URI getURI() {
        return uri;
    }

    /**
     * Returns the protocol version this channel uses.
 For more infos see
     * http://example.com
     *
     * @return The draft used for this client
     */
    public Draft getDraft() {
        return draft;
    }

    /**
     * Returns the socket to allow Hostname Verification
     *
     * @return the socket used for this connection
     */
    public Socket getSocket() {
        return socket;
    }

    /**
     * @param key   Name of the header to add.
     * @param value Value of the header to add.
     * @since 1.4.1 Adds an additional header to be sent in the handshake.
 If the connection is
     * already made, adding headers has no effect, unless reconnect is called, which then a new
     * handshake is sent.
 If a header with the same key already exists, it is overridden.
     */
    public void addHeader(String key, String value) {
        if (headers == null) {
            headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        }
        headers.put(key, value);
    }

    /**
     * @param key Name of the header to remove.
     * @return the previous value associated with key, or null if there was no mapping for key.
     * @since 1.4.1 Removes a header from the handshake to be sent, if header key exists.

     */
    public String removeHeader(String key) {
        if (headers == null) {
            return null;
        }
        return headers.remove(key);
    }

    /**
     * @since 1.4.1 Clears all previously put headers.
     */
    public void clearHeaders() {
        headers = null;
    }

    /**
     * Sets a custom DNS resolver.
     *
     * @param dnsResolver The DnsResolver to use.
     * @since 1.4.1
     */
    public void setDnsResolver(DnsResolver dnsResolver) {
        this.dnsResolver = dnsResolver;
    }

    /**
     * Reinitiates the websocket connection. This method does not block.
     *
     * @since 1.3.8
     */
    public void reconnect() {
        reset();
        connect();
    }

    /**
     * Same as reconnect but blocks until the websocket reconnected or failed to do
     * so.

     *
     * @return Returns whether it succeeded or not.
     * @throws InterruptedException Thrown when the threads get interrupted
     * @since 1.3.8
     */
    public boolean reconnectBlocking() throws InterruptedException {
        reset();
        return connectBlocking();
    }

    /**
     * Reset everything relevant to allow a reconnect
     *
     * @since 1.3.8
     */
    private void reset() {
        Thread current = Thread.currentThread();
        if (current == writeThread || current == connectReadThread) {
            throw new IllegalStateException("You cannot initialize a reconnect out of the websocket thread. Use reconnect in another thread to ensure a successful cleanup.");
        }
        try {
            closeBlocking();
            if (writeThread != null) {
                this.writeThread.interrupt();
                this.writeThread = null;
            }
            if (connectReadThread != null) {
                this.connectReadThread.interrupt();
                this.connectReadThread = null;
            }
            this.draft.reset();
            if (this.socket != null) {
                this.socket.close();
                this.socket = null;
            }
        } catch (Exception e) {
            onError(e);
            engine.closeConnection(CloseFrame.ABNORMAL_CLOSE, e.getMessage());
            return;
        }
        connectLatch = new CountDownLatch(1);
        closeLatch = new CountDownLatch(1);
        this.engine = new WebSocketImpl(this, this.draft);
    }

    /**
     * Initiates the websocket connection. This method does not block.
     */
    public void connect() {
        if (connectReadThread != null) {
            throw new IllegalStateException("WebSocketClient objects are not reuseable");
        }
        connectReadThread = new Thread(this);
        connectReadThread.setName("WebSocketConnectReadThread-" + connectReadThread.getId());
        connectReadThread.start();
    }

    /**
     * Same as connect but blocks until the websocket connected or failed to do so.

     *
     * @return Returns whether it succeeded or not.
     * @throws InterruptedException Thrown when the threads get interrupted
     */
    public boolean connectBlocking() throws InterruptedException {
        connect();
        connectLatch.await();
        return engine.isOpen();
    }

    /**
     * Same as connect but blocks with a timeout until the websocket connected or failed
     * to do so.

     *
     * @param timeout  The connect timeout
     * @param timeUnit The timeout time unit
     * @return Returns whether it succeeded or not.
     * @throws InterruptedException Thrown when the threads get interrupted
     */
    public boolean connectBlocking(long timeout, TimeUnit timeUnit) throws InterruptedException {
        connect();
        return connectLatch.await(timeout, timeUnit) && engine.isOpen();
    }

    /**
     * Initiates the websocket close handshake. This method does not block
 In oder to make sure
     * the connection is closed use closeBlocking
     */
    public void close() {
        if (writeThread != null) {
            engine.close(CloseFrame.NORMAL);
        }
    }

    /**
     * Same as close but blocks until the websocket closed or failed to do so.

     *
     * @throws InterruptedException Thrown when the threads get interrupted
     */
    public void closeBlocking() throws InterruptedException {
        close();
        closeLatch.await();
    }

    /**
     * Sends <var>text</var> to the connected websocket server.
     *
     * @param text The string which will be transmitted.
     */
    public void send(String text) {
        engine.send(text);
    }

    /**
     * Sends binary <var> data</var> to the connected webSocket server.
     *
     * @param data The byte-Array of data to send to the WebSocket server.
     */
    public void send(byte[] data) {
        engine.send(data);
    }

    @Override
    public <T> T getAttachment() {
        return engine.getAttachment();
    }

    @Override
    public <T> void setAttachment(T attachment) {
        engine.setAttachment(attachment);
    }

    @Override
    protected Collection<WebSocket> getConnections() {
        return Collections.singletonList((WebSocket) engine);
    }

    @Override
    public void sendPing() {
        engine.sendPing();
    }

    public void run() {
        InputStream istream;
        try {
            boolean upgradeSocketToSSLSocket = prepareSocket();
            socket.setTcpNoDelay(isTcpNoDelay());
            socket.setReuseAddress(isReuseAddr());
            if (!socket.isConnected()) {
                InetSocketAddress addr = dnsResolver == null ? InetSocketAddress.createUnresolved(uri.getHost(), getPort()) : new InetSocketAddress(dnsResolver.resolve(uri), this.getPort());
                socket.connect(addr, connectTimeout);
            }
            // if the socket is set by others we don't apply any TLS wrapper
            if (upgradeSocketToSSLSocket && "wss".equals(uri.getScheme())) {
                upgradeSocketToSSL();
            }
            if (socket instanceof SSLSocket) {
                SSLSocket sslSocket = (SSLSocket) socket;
                SSLParameters sslParameters = sslSocket.getSSLParameters();
                onSetSSLParameters(sslParameters);
                sslSocket.setSSLParameters(sslParameters);
            }
            istream = socket.getInputStream();
            ostream = socket.getOutputStream();
            sendHandshake();
        } catch (/*IOException | SecurityException | UnresolvedAddressException | InvalidHandshakeException | ClosedByInterruptException | SocketTimeoutException */
        Exception e) {
            onWebsocketError(engine, e);
            engine.closeConnection(CloseFrame.NEVER_CONNECTED, e.getMessage());
            return;
        } catch (InternalError e) {
            if (e.getCause() instanceof InvocationTargetException && e.getCause().getCause() instanceof IOException) {
                IOException cause = (IOException) e.getCause().getCause();
                onWebsocketError(engine, cause);
                engine.closeConnection(CloseFrame.NEVER_CONNECTED, cause.getMessage());
                return;
            }
            throw e;
        }
        writeThread = new Thread(new WebsocketWriteThread(this));
        writeThread.start();
        byte[] rawbuffer = new byte[WebSocketImpl.RCVBUF];
        int readBytes;
        try {
            while (!isClosing() && !isClosed() && (readBytes = istream.read(rawbuffer)) != -1) {
                engine.decode(ByteBuffer.wrap(rawbuffer, 0, readBytes));
            }
            engine.eot();
        } catch (IOException e) {
            handleIOException(e);
        } catch (RuntimeException e) {
            // this catch case covers internal errors only and indicates a bug in this websocket implementation
            onError(e);
            engine.closeConnection(CloseFrame.ABNORMAL_CLOSE, e.getMessage());
        }
        connectReadThread = null;
    }

    private void upgradeSocketToSSL() throws NoSuchAlgorithmException, KeyManagementException, IOException {
        SSLSocketFactory factory;
        // Prioritise the provided socketfactory
        // Helps when using web debuggers like Fiddler Classic
        if (socketFactory instanceof SSLSocketFactory) {
            factory = (SSLSocketFactory) socketFactory;
        } else {
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, null, null);
            factory = sslContext.getSocketFactory();
        }
        socket = factory.createSocket(socket, uri.getHost(), getPort(), true);
    }

    private boolean prepareSocket() throws IOException {
        boolean upgradeSocketToSSLSocket = false;
        // Prioritise a proxy over a socket factory and apply the socketfactory later
        if (proxy != Proxy.NO_PROXY) {
            socket = new Socket(proxy);
            upgradeSocketToSSLSocket = true;
        } else if (socketFactory != null) {
            socket = socketFactory.createSocket();
        } else if (socket == null) {
            socket = new Socket(proxy);
            upgradeSocketToSSLSocket = true;
        } else if (socket.isClosed()) {
            throw new IOException();
        }
        return upgradeSocketToSSLSocket;
    }

    /**
     * Apply specific SSLParameters If you override this method make sure to always call
     * super.onSetSSLParameters() to ensure the hostname validation is active
     *
     * @param sslParameters the SSLParameters which will be used for the SSLSocket
     */
    protected void onSetSSLParameters(SSLParameters sslParameters) {
        // If you run into problem on Android (NoSuchMethodException), check out the wiki http://example.com
        // Perform hostname validation
        sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
    }

    /**
     * Extract the specified port
     *
     * @return the specified port or the default port for the specific scheme
     */
    private int getPort() {
        int port = uri.getPort();
        String scheme = uri.getScheme();
        if ("wss".equals(scheme)) {
            return port == -1 ? WebSocketImpl.DEFAULT_WSS_PORT : port;
        } else if ("ws".equals(scheme)) {
            return port == -1 ? WebSocketImpl.DEFAULT_PORT : port;
        } else {
            throw new IllegalArgumentException("unknown scheme: " + scheme);
        }
    }

    /**
     * Create and send the handshake to the other endpoint
     *
     * @throws InvalidHandshakeException a invalid handshake was created
     */
    private void sendHandshake() throws InvalidHandshakeException {
        String path;
        String part1 = uri.getRawPath();
        String part2 = uri.getRawQuery();
        if (part1 == null || part1.length() == 0) {
            path = "/";
        } else {
            path = part1;
        }
        if (part2 != null) {
            path += '?' + part2;
        }
        int port = getPort();
        String host = uri.getHost() + ((port != WebSocketImpl.DEFAULT_PORT && port != WebSocketImpl.DEFAULT_WSS_PORT) ? ":" + port : "");
        HandshakeImpl1Client handshake = new HandshakeImpl1Client();
        handshake.setResourceDescriptor(path);
        handshake.put("Host", host);
        if (headers != null) {
            for (Map.Entry<String, String> kv : headers.entrySet()) {
                handshake.put(kv.getKey(), kv.getValue());
            }
        }
        engine.startHandshake(handshake);
    }

    /**
     * This represents the state of the connection.
     */
    public ReadyState getReadyState() {
        return engine.getReadyState();
    }

    @Override
    public final void onWebsocketMessage(WebSocket conn, String message) {
        onMessage(message);
    }

    @Override
    public final void onWebsocketMessage(WebSocket conn, ByteBuffer blob) {
        onMessage(blob);
    }

    @Override
    public final void onWebsocketOpen(WebSocket conn, Handshakedata handshake) {
        startConnectionLostTimer();
        onOpen((ServerHandshake) handshake);
        connectLatch.countDown();
    }

    @Override
    public final void onWebsocketClose(WebSocket conn, int code, String reason, boolean remote) {
        stopConnectionLostTimer();
        if (writeThread != null) {
            writeThread.interrupt();
        }
        onClose(code, reason, remote);
        connectLatch.countDown();
        closeLatch.countDown();
    }

    @Override
    public final void onWebsocketError(WebSocket conn, Exception ex) {
        onError(ex);
    }

    @Override
    public final void onWriteDemand(WebSocket conn) {
        // nothing to do
    }

    @Override
    public void onWebsocketCloseInitiated(WebSocket conn, int code, String reason) {
        onCloseInitiated(code, reason);
    }

    @Override
    public void onWebsocketClosing(WebSocket conn, int code, String reason, boolean remote) {
        onClosing(code, reason, remote);
    }

    /**
     * Send when this peer sends a close handshake
     *
     * @param code   The codes can be looked up here: {@link CloseFrame}
     * @param reason Additional information string
     */
    public void onCloseInitiated(int code, String reason) {
        // To overwrite
    }

    /**
     * Called as soon as no further frames are accepted
     *
     * @param code   The codes can be looked up here: {@link CloseFrame}
     * @param reason Additional information string
     * @param remote Returns whether or not the closing of the connection was initiated by the remote
     *               host.
     */
    public void onClosing(int code, String reason, boolean remote) {
        // To overwrite
    }

    /**
     * Getter for the engine
     *
     * @return the engine
     */
    public WebSocket getConnection() {
        return engine;
    }

    @Override
    public InetSocketAddress getLocalSocketAddress(WebSocket conn) {
        if (socket != null) {
            return (InetSocketAddress) socket.getLocalSocketAddress();
        }
        return null;
    }

    @Override
    public InetSocketAddress getRemoteSocketAddress(WebSocket conn) {
        if (socket != null) {
            return (InetSocketAddress) socket.getRemoteSocketAddress();
        }
        return null;
    }

    /**
     * Called after an opening handshake has been performed and the given websocket is ready to be
     * written on.
     *
     * @param handshakedata The handshake of the websocket instance
     */
    public abstract void onOpen(ServerHandshake handshakedata);

    /**
     * Callback for string messages received from the remote host
     *
     * @param message The UTF-8 decoded message that was received.
     * @see #onMessage(ByteBuffer)
     */
    public abstract void onMessage(String message);

    /**
     * Called after the websocket connection has been closed.
     *
     * @param code   The codes can be looked up here: {@link CloseFrame}
     * @param reason Additional information string
     * @param remote Returns whether or not the closing of the connection was initiated by the remote
     *               host.
     */
    public abstract void onClose(int code, String reason, boolean remote);

    /**
     * Called when errors occurs. If an error causes the websocket connection to fail {@link
     * #onClose(int, String, boolean)} will be called additionally.
 This method will be called
     * primarily because of IO or protocol errors.
 If the given exception is an RuntimeException
     * that probably means that you encountered a bug.

     *
     * @param ex The exception causing this error
     */
    public abstract void onError(Exception ex);

    /**
     * Callback for binary messages received from the remote host
     *
     * @param bytes The binary message that was received.
     * @see #onMessage(String)
     */
    public void onMessage(ByteBuffer bytes) {
        // To overwrite
    }

    private class WebsocketWriteThread implements Runnable {

        private final WebSocketClient webSocketClient;

        WebsocketWriteThread(WebSocketClient webSocketClient) {
            this.webSocketClient = webSocketClient;
        }

        @Override
        public void run() {
            Thread.currentThread().setName("WebSocketWriteThread-" + Thread.currentThread().getId());
            try {
                runWriteData();
            } catch (IOException e) {
                handleIOException(e);
            } finally {
                closeSocket();
                writeThread = null;
            }
        }

        /**
         * Write the data into the outstream
         *
         * @throws IOException if write or flush did not work
         */
        private void runWriteData() throws IOException {
            try {
                while (!Thread.interrupted()) {
                    ByteBuffer buffer = engine.outQueue.take();
                    ostream.write(buffer.array(), 0, buffer.limit());
                    ostream.flush();
                }
            } catch (InterruptedException e) {
                for (ByteBuffer buffer : engine.outQueue) {
                    ostream.write(buffer.array(), 0, buffer.limit());
                    ostream.flush();
                }
                Thread.currentThread().interrupt();
            }
        }

        /**
         * Closing the socket
         */
        private void closeSocket() {

}
    }

    /**
     * Method to set a proxy for this connection
     *
     * @param proxy the proxy to use for this websocket client
     */
    public void setProxy(Proxy proxy) {
        if (proxy == null) {
            throw new IllegalArgumentException();
        }
        this.proxy = proxy;
    }

    /**
     * Accepts bound and unbound sockets.
 This method must be called before connect.
     * If the given socket is not yet bound it will be bound to the uri specified in the constructor.
     *
     * @param socket The socket which should be used for the connection
     * @deprecated use setSocketFactory
     */
    @Deprecated
    public void setSocket(Socket socket) {
        if (this.socket != null) {
            throw new IllegalStateException("socket has already been set");
        }
        this.socket = socket;
    }

    /**
     * Accepts a SocketFactory.
 This method must be called before connect. The socket
     * will be bound to the uri specified in the constructor.
     *
     * @param socketFactory The socket factory which should be used for the connection.
     */
    public void setSocketFactory(SocketFactory socketFactory) {
        this.socketFactory = socketFactory;
    }

    @Override
    public void sendFragmentedFrame(Opcode op, ByteBuffer buffer, boolean fin) {
        engine.sendFragmentedFrame(op, buffer, fin);
    }

    @Override
    public boolean isOpen() {
        return engine.isOpen();
    }

    @Override
    public boolean isFlushAndClose() {
        return engine.isFlushAndClose();
    }

    @Override
    public boolean isClosed() {
        return engine.isClosed();
    }

    @Override
    public boolean isClosing() {
        return engine.isClosing();
    }

    @Override
    public boolean hasBufferedData() {
        return engine.hasBufferedData();
    }

    @Override
    public void close(int code) {
        engine.close(code);
    }

    @Override
    public void close(int code, String message) {
        engine.close(code, message);
    }

    @Override
    public void closeConnection(int code, String message) {
        engine.closeConnection(code, message);
    }

    @Override
    public void send(ByteBuffer bytes) {
        engine.send(bytes);
    }

    @Override
    public void sendFrame(Framedata framedata) {
        engine.sendFrame(framedata);
    }

    @Override
    public void sendFrame(Collection<Framedata> frames) {
        engine.sendFrame(frames);
    }

    @Override
    public InetSocketAddress getLocalSocketAddress() {
        return engine.getLocalSocketAddress();
    }

    @Override
    public InetSocketAddress getRemoteSocketAddress() {
        return engine.getRemoteSocketAddress();
    }

    @Override
    public String getResourceDescriptor() {
        return uri.getPath();
    }

    @Override
    public boolean hasSSLSupport() {
        return socket instanceof SSLSocket;
    }

    @Override
    public SSLSession getSSLSession() {
        if (!hasSSLSupport()) {
            throw new IllegalArgumentException("This websocket uses ws instead of wss. No SSLSession available.");
        }
        return ((SSLSocket) socket).getSession();
    }

    @Override
    public IProtocol getProtocol() {
        return engine.getProtocol();
    }

    /**
     * Method to give some additional info for specific IOExceptions
     *
     * @param e the IOException causing a eot.
     */
    private void handleIOException(IOException e) {
        if (e instanceof SSLException) {
            onError(e);
        }
        engine.eot();
    }
}


protected void transformSpace(Rectangle rect) {
    }

package com.jhlabs.image;

import net.jafama.FastMath;
import pixelitor.ThreadPool;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * An abstract superclass for filters which distort images in some way. The subclass only needs to override
 * two methods to provide the mapping between source and destination pixels.
 */
public abstract class TransformFilter extends AbstractBufferedImageOp {

    // image dimensions
    protected int srcWidth;

    protected int srcHeight;

    /**
     * Treat pixels off the edge as zero.
     */
    public static final int TRANSPARENT = 0;

    /**
     * Clamp pixels to the image edges.
     */
    public static final int REPEAT_EDGE_PIXELS = 1;

    /**
     * Wrap pixels off the edge onto the opposite edge.
     */
    public static final int WRAP_AROUND = 2;

    /**
     * Clamp pixels RGB to the image edges, but zero the alpha. This prevents gray borders on your image.
     */
    public static final int RGB_CLAMP = 3;

    public static final int REFLECT = 4;

    public static final int NEAREST_NEIGHBOUR = 0;

    public static final int NEAREST_NEIGHBOUR_OLD = 2;

    public static final int BILINEAR = 1;

    public static final int BILINEAR_OLD = 3;

    /**
     * The action to take for pixels off the image edge.
     */
    protected int edgeAction = RGB_CLAMP;

    /**
     * The type of interpolation to use.
     */
    protected int interpolation = BILINEAR;

    /**
     * The output image rectangle.
     */
    /**
     * The input image rectangle.
     */
    protected TransformFilter(String filterName) {
        super(filterName);
    }

    /**
     * Set the action to perform for pixels off the edge of the image.
     *
     * @param edgeAction one of TRANSPARENT, REPEAT_EDGE_PIXELS or WRAP_AROUND
     * @see #getEdgeAction
     */
    public void setEdgeAction(int edgeAction) {
        this.edgeAction = edgeAction;
    }

    /**
     * Get the action to perform for pixels off the edge of the image.
     *
     * @return one of TRANSPARENT, REPEAT_EDGE_PIXELS or WRAP_AROUND
     * @see #setEdgeAction
     */
    public int getEdgeAction() {
        return edgeAction;
    }

    /**
     * Set the type of interpolation to perform.
     *
     * @param interpolation one of NEAREST_NEIGHBOUR or BILINEAR
     * @see #getInterpolation
     */
    public void setInterpolation(int interpolation) {
        this.interpolation = interpolation;
    }

    /**
     * Get the type of interpolation to perform.
     *
     * @return one of NEAREST_NEIGHBOUR or BILINEAR
     * @see #setInterpolation
     */
    public int getInterpolation() {
        return interpolation;
    }

    /**
     * Inverse transform a point. This method needs to be overriden by all subclasses.
     *
     * @param x   the X position of the pixel in the output image
     * @param y   the Y position of the pixel in the output image
     * @param out the position of the pixel in the input image
     */
    protected abstract void transformInverse(int x, int y, float[] out);

    /**
     * Forward transform a rectangle. Used to determine the size of the output image.
     *
     * @param rect the rectangle to transform
     */

    @Override
    public BufferedImage filter(BufferedImage src, BufferedImage dst) {
        srcWidth = src.getWidth();
        srcHeight = src.getHeight();
        // lbalazscs: commented out space transformation because it is not used anyway
        // (in the Filters used by pixelitor)
        if (dst == null) {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(0, 0), dstCM.isAlphaPremultiplied(), null);
        }
        int[] inPixels = getRGB(src, 0, 0, srcWidth, srcHeight, null);
        if (interpolation == BILINEAR) {
            return filterPixelsBilinear(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == NEAREST_NEIGHBOUR) {
            return filterPixelsNN(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == BILINEAR_OLD) {
            return filterPixelsBilinearOLD(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == NEAREST_NEIGHBOUR_OLD) {
            return filterPixelsNNOLD(dst, srcWidth, srcHeight, inPixels);
        }
        throw new IllegalStateException("should not get here");
    }

    private BufferedImage filterPixelsBilinearOLD(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int srcWidth1 = width - 1;
        int srcHeight1 = height - 1;
        int outWidth = width;
        int outHeight = height;
        int[] outPixels = new int[outWidth];
        float[] out = new float[2];
        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(x, y, out);
                int srcX = (int) FastMath.floor(out[0]);
                int srcY = (int) FastMath.floor(out[1]);
                float xWeight = out[0] - srcX;
                float yWeight = out[1] - srcY;
                int nw, ne, sw, se;
                if ((srcX >= 0) && (srcX < srcWidth1) && (srcY >= 0) && (srcY < srcHeight1)) {
                    // Easy case, all corners are in the image
                    int i = (srcWidth * srcY) + srcX;
                    nw = inPixels[i];
                    ne = inPixels[i + 1];
                    sw = inPixels[i + srcWidth];
                    se = inPixels[i + srcWidth + 1];
                } else {
                    // Some of the corners are off the image
                    nw = getPixelBL(inPixels, srcX, srcY, srcWidth, srcHeight);
                    ne = getPixelBL(inPixels, srcX + 1, srcY, srcWidth, srcHeight);
                    sw = getPixelBL(inPixels, srcX, srcY + 1, srcWidth, srcHeight);
                    se = getPixelBL(inPixels, srcX + 1, srcY + 1, srcWidth, srcHeight);
                }
                outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
            }
            setRGB(dst, 0, y, width, 1, outPixels);
        }
        return dst;
    }

    protected BufferedImage filterPixelsNNOLD(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int outWidth = width;
        int outHeight = height;
        int[] outPixels = new int[outWidth];
        float[] out = new float[2];
        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(x, y, out);
                int srcX = (int) out[0];
                int srcY = (int) out[1];
                // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
                outPixels[x] = getPixelNN(inPixels, srcWidth, srcHeight, srcX, srcY, out);
            }
            setRGB(dst, 0, y, width, 1, outPixels);
        }
        return dst;
    }

    protected BufferedImage filterPixelsNN(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int outWidth = width;
        int outHeight = height;
        pt = createProgressTracker(outHeight);
        @SuppressWarnings("unchecked")
        Future<int[]>[] resultLines = new Future[outHeight];
        for (int y = 0; y < outHeight; y++) {
            float[] out = new float[2];
            int finalY = y;
            Callable<int[]> calculateLineTask = () -> {
                int srcX, srcY;
                int[] outPixels = new int[outWidth];
                for (int x = 0; x < outWidth; x++) {
                    transformInverse(x, finalY, out);
                    srcX = (int) out[0];
                    srcY = (int) out[1];
                    // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
                    outPixels[x] = getPixelNN(inPixels, srcWidth, srcHeight, srcX, srcY, out);
                }
                return outPixels;
            };
            resultLines[finalY] = ThreadPool.submit2(calculateLineTask);
        }
        ThreadPool.waitFor2(resultLines, dst, width, pt);
        finishProgressTracker();
        return dst;
    }

    private BufferedImage filterPixelsBilinear(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int srcWidth1 = width - 1;
        int srcHeight1 = height - 1;
        int outWidth = width;
        int outHeight = height;
        pt = createProgressTracker(outHeight);
        @SuppressWarnings("unchecked")
        Future<int[]>[] resultLines = new Future[outHeight];
        for (int y = 0; y < outHeight; y++) {
            float[] out = new float[2];
            int finalY = y;
            Callable<int[]> calculateLineTask = () -> {
                int[] outPixels = new int[outWidth];
                for (int x = 0; x < outWidth; x++) {
                    transformInverse(x, finalY, out);
                    int srcX = (int) FastMath.floor(out[0]);
                    int srcY = (int) FastMath.floor(out[1]);
                    float xWeight = out[0] - srcX;
                    float yWeight = out[1] - srcY;
                    int nw, ne, sw, se;
                    if ((srcX >= 0) && (srcX < srcWidth1) && (srcY >= 0) && (srcY < srcHeight1)) {
                        // Easy case, all corners are in the image
                        int i = (srcWidth * srcY) + srcX;
                        nw = inPixels[i];
                        ne = inPixels[i + 1];
                        sw = inPixels[i + srcWidth];
                        se = inPixels[i + srcWidth + 1];
                    } else {
                        // Some of the corners are off the image
                        nw = getPixelBL(inPixels, srcX, srcY, srcWidth, srcHeight);
                        ne = getPixelBL(inPixels, srcX + 1, srcY, srcWidth, srcHeight);
                        sw = getPixelBL(inPixels, srcX, srcY + 1, srcWidth, srcHeight);
                        se = getPixelBL(inPixels, srcX + 1, srcY + 1, srcWidth, srcHeight);
                    }
                    outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
                }
                return outPixels;
            };
            resultLines[finalY] = ThreadPool.submit2(calculateLineTask);
        }
        ThreadPool.waitFor2(resultLines, dst, width, pt);
        finishProgressTracker();
        return dst;
    }

    private int getPixelBL(int[] pixels, int x, int y, int width, int height) {
        if ((x < 0) || (x >= width)) {
            // x out of range
            if ((y < 0) || (y >= height)) {
                // y also out of range {
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(x, width);
                        int reflectedY = ImageMath.reflectTriangle(y, height);
                        return pixels[(reflectedY * width) + reflectedX];
                }
            } else {
                // x out of range, but y is OK
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(y * width) + ImageMath.mod(x, width)];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(y * width) + ImageMath.clamp(x, 0, width - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(x, width);
                        return pixels[(y * width) + reflectedX];
                }
            }
        } else {
            // x in range
            if ((y < 0) || (y >= height)) {
                // ... but y is out
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(ImageMath.mod(y, height) * width) + x];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(ImageMath.clamp(y, 0, height - 1) * width) + x];
                    case REFLECT:
                        int reflectedY = ImageMath.reflectTriangle(y, height);
                        return pixels[(reflectedY * width) + x];
                }
            } else {
                // both x and y are OK
                return pixels[((y * width) + x)];
            }
        }
    }

    private int getPixelNN(int[] inPixels, int srcWidth, int srcHeight, int srcX, int srcY, float[] out) {
        if ((out[0] < 0) || (srcX >= srcWidth)) {
            // x out of range
            if ((out[1] < 0) || (srcY >= srcHeight)) {
                // y also out of range
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(ImageMath.mod(srcY, srcHeight) * srcWidth) + ImageMath.mod(srcX, srcWidth)];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(srcX, srcWidth);
                        int reflectedY = ImageMath.reflectTriangle(srcY, srcHeight);
                        return inPixels[(reflectedY * srcWidth) + reflectedX];
                }
            } else {
                // x out of range, but y is OK
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(srcY * srcWidth) + ImageMath.mod(srcX, srcWidth)];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(srcY * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(srcX, srcWidth);
                        return inPixels[(srcY * srcWidth) + reflectedX];
                }
            }
        } else {
            // x in range
            if ((out[1] < 0) || (srcY >= srcHeight)) {
                // ... but y isn't
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(ImageMath.mod(srcY, srcHeight) * srcWidth) + srcX];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + srcX];
                    case REFLECT:
                        int reflectedY = ImageMath.reflectTriangle(srcY, srcHeight);
                        return inPixels[(reflectedY * srcWidth) + srcX];
                }
            } else {
                // both x and y are OK
                int i = (srcWidth * srcY) + srcX;
                return inPixels[i];
            }
        }
    }
}


for (int x = 0; x < outWidth; x++) {
                    transformInverse(x, finalY, out);
                    srcX = (int) out[0];
                    srcY = (int) out[1];
                    // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
                    outPixels[x] = getPixelNN(inPixels, srcWidth, srcHeight, srcX, srcY, out);
                }

package com.jhlabs.image;

import net.jafama.FastMath;
import pixelitor.ThreadPool;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
 * An abstract superclass for filters which distort images in some way. The subclass only needs to override
 * two methods to provide the mapping between source and destination pixels.
 */
public abstract class TransformFilter extends AbstractBufferedImageOp {

    // image dimensions
    protected int srcWidth;

    protected int srcHeight;

    /**
     * Treat pixels off the edge as zero.
     */
    public static final int TRANSPARENT = 0;

    /**
     * Clamp pixels to the image edges.
     */
    public static final int REPEAT_EDGE_PIXELS = 1;

    /**
     * Wrap pixels off the edge onto the opposite edge.
     */
    public static final int WRAP_AROUND = 2;

    /**
     * Clamp pixels RGB to the image edges, but zero the alpha. This prevents gray borders on your image.
     */
    public static final int RGB_CLAMP = 3;

    public static final int REFLECT = 4;

    public static final int NEAREST_NEIGHBOUR = 0;

    public static final int NEAREST_NEIGHBOUR_OLD = 2;

    public static final int BILINEAR = 1;

    public static final int BILINEAR_OLD = 3;

    /**
     * The action to take for pixels off the image edge.
     */
    protected int edgeAction = RGB_CLAMP;

    /**
     * The type of interpolation to use.
     */
    protected int interpolation = BILINEAR;

    /**
     * The output image rectangle.
     */
    /**
     * The input image rectangle.
     */
    protected TransformFilter(String filterName) {
        super(filterName);
    }

    /**
     * Set the action to perform for pixels off the edge of the image.
     *
     * @param edgeAction one of TRANSPARENT, REPEAT_EDGE_PIXELS or WRAP_AROUND
     * @see #getEdgeAction
     */
    public void setEdgeAction(int edgeAction) {
        this.edgeAction = edgeAction;
    }

    /**
     * Get the action to perform for pixels off the edge of the image.
     *
     * @return one of TRANSPARENT, REPEAT_EDGE_PIXELS or WRAP_AROUND
     * @see #setEdgeAction
     */
    public int getEdgeAction() {
        return edgeAction;
    }

    /**
     * Set the type of interpolation to perform.
     *
     * @param interpolation one of NEAREST_NEIGHBOUR or BILINEAR
     * @see #getInterpolation
     */
    public void setInterpolation(int interpolation) {
        this.interpolation = interpolation;
    }

    /**
     * Get the type of interpolation to perform.
     *
     * @return one of NEAREST_NEIGHBOUR or BILINEAR
     * @see #setInterpolation
     */
    public int getInterpolation() {
        return interpolation;
    }

    /**
     * Inverse transform a point. This method needs to be overriden by all subclasses.
     *
     * @param x   the X position of the pixel in the output image
     * @param y   the Y position of the pixel in the output image
     * @param out the position of the pixel in the input image
     */
    protected abstract void transformInverse(int x, int y, float[] out);

    /**
     * Forward transform a rectangle. Used to determine the size of the output image.
     *
     * @param rect the rectangle to transform
     */
    protected void transformSpace(Rectangle rect) {
    }

    @Override
    public BufferedImage filter(BufferedImage src, BufferedImage dst) {
        srcWidth = src.getWidth();
        srcHeight = src.getHeight();
        // lbalazscs: commented out space transformation because it is not used anyway
        // (in the Filters used by pixelitor)
        if (dst == null) {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(0, 0), dstCM.isAlphaPremultiplied(), null);
        }
        int[] inPixels = getRGB(src, 0, 0, srcWidth, srcHeight, null);
        if (interpolation == BILINEAR) {
            return filterPixelsBilinear(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == NEAREST_NEIGHBOUR) {
            return filterPixelsNN(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == BILINEAR_OLD) {
            return filterPixelsBilinearOLD(dst, srcWidth, srcHeight, inPixels);
        } else if (interpolation == NEAREST_NEIGHBOUR_OLD) {
            return filterPixelsNNOLD(dst, srcWidth, srcHeight, inPixels);
        }
        throw new IllegalStateException("should not get here");
    }

    private BufferedImage filterPixelsBilinearOLD(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int srcWidth1 = width - 1;
        int srcHeight1 = height - 1;
        int outWidth = width;
        int outHeight = height;
        int[] outPixels = new int[outWidth];
        float[] out = new float[2];
        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(x, y, out);
                int srcX = (int) FastMath.floor(out[0]);
                int srcY = (int) FastMath.floor(out[1]);
                float xWeight = out[0] - srcX;
                float yWeight = out[1] - srcY;
                int nw, ne, sw, se;
                if ((srcX >= 0) && (srcX < srcWidth1) && (srcY >= 0) && (srcY < srcHeight1)) {
                    // Easy case, all corners are in the image
                    int i = (srcWidth * srcY) + srcX;
                    nw = inPixels[i];
                    ne = inPixels[i + 1];
                    sw = inPixels[i + srcWidth];
                    se = inPixels[i + srcWidth + 1];
                } else {
                    // Some of the corners are off the image
                    nw = getPixelBL(inPixels, srcX, srcY, srcWidth, srcHeight);
                    ne = getPixelBL(inPixels, srcX + 1, srcY, srcWidth, srcHeight);
                    sw = getPixelBL(inPixels, srcX, srcY + 1, srcWidth, srcHeight);
                    se = getPixelBL(inPixels, srcX + 1, srcY + 1, srcWidth, srcHeight);
                }
                outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
            }
            setRGB(dst, 0, y, width, 1, outPixels);
        }
        return dst;
    }

    protected BufferedImage filterPixelsNNOLD(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int outWidth = width;
        int outHeight = height;
        int[] outPixels = new int[outWidth];
        float[] out = new float[2];
        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(x, y, out);
                int srcX = (int) out[0];
                int srcY = (int) out[1];
                // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
                outPixels[x] = getPixelNN(inPixels, srcWidth, srcHeight, srcX, srcY, out);
            }
            setRGB(dst, 0, y, width, 1, outPixels);
        }
        return dst;
    }

    protected BufferedImage filterPixelsNN(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int outWidth = width;
        int outHeight = height;
        pt = createProgressTracker(outHeight);
        @SuppressWarnings("unchecked")
        Future<int[]>[] resultLines = new Future[outHeight];
        for (int y = 0; y < outHeight; y++) {
            float[] out = new float[2];
            int finalY = y;
            Callable<int[]> calculateLineTask = () -> {
                int srcX, srcY;
                int[] outPixels = new int[outWidth];

                return outPixels;
            };
            resultLines[finalY] = ThreadPool.submit2(calculateLineTask);
        }
        ThreadPool.waitFor2(resultLines, dst, width, pt);
        finishProgressTracker();
        return dst;
    }

    private BufferedImage filterPixelsBilinear(BufferedImage dst, int width, int height, int[] inPixels) {
        int srcWidth = width;
        int srcHeight = height;
        int srcWidth1 = width - 1;
        int srcHeight1 = height - 1;
        int outWidth = width;
        int outHeight = height;
        pt = createProgressTracker(outHeight);
        @SuppressWarnings("unchecked")
        Future<int[]>[] resultLines = new Future[outHeight];
        for (int y = 0; y < outHeight; y++) {
            float[] out = new float[2];
            int finalY = y;
            Callable<int[]> calculateLineTask = () -> {
                int[] outPixels = new int[outWidth];
                for (int x = 0; x < outWidth; x++) {
                    transformInverse(x, finalY, out);
                    int srcX = (int) FastMath.floor(out[0]);
                    int srcY = (int) FastMath.floor(out[1]);
                    float xWeight = out[0] - srcX;
                    float yWeight = out[1] - srcY;
                    int nw, ne, sw, se;
                    if ((srcX >= 0) && (srcX < srcWidth1) && (srcY >= 0) && (srcY < srcHeight1)) {
                        // Easy case, all corners are in the image
                        int i = (srcWidth * srcY) + srcX;
                        nw = inPixels[i];
                        ne = inPixels[i + 1];
                        sw = inPixels[i + srcWidth];
                        se = inPixels[i + srcWidth + 1];
                    } else {
                        // Some of the corners are off the image
                        nw = getPixelBL(inPixels, srcX, srcY, srcWidth, srcHeight);
                        ne = getPixelBL(inPixels, srcX + 1, srcY, srcWidth, srcHeight);
                        sw = getPixelBL(inPixels, srcX, srcY + 1, srcWidth, srcHeight);
                        se = getPixelBL(inPixels, srcX + 1, srcY + 1, srcWidth, srcHeight);
                    }
                    outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
                }
                return outPixels;
            };
            resultLines[finalY] = ThreadPool.submit2(calculateLineTask);
        }
        ThreadPool.waitFor2(resultLines, dst, width, pt);
        finishProgressTracker();
        return dst;
    }

    private int getPixelBL(int[] pixels, int x, int y, int width, int height) {
        if ((x < 0) || (x >= width)) {
            // x out of range
            if ((y < 0) || (y >= height)) {
                // y also out of range {
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(x, width);
                        int reflectedY = ImageMath.reflectTriangle(y, height);
                        return pixels[(reflectedY * width) + reflectedX];
                }
            } else {
                // x out of range, but y is OK
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(y * width) + ImageMath.mod(x, width)];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(y * width) + ImageMath.clamp(x, 0, width - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(x, width);
                        return pixels[(y * width) + reflectedX];
                }
            }
        } else {
            // x in range
            if ((y < 0) || (y >= height)) {
                // ... but y is out
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return pixels[(ImageMath.mod(y, height) * width) + x];
                    case REPEAT_EDGE_PIXELS:
                        return pixels[(ImageMath.clamp(y, 0, height - 1) * width) + x];
                    case REFLECT:
                        int reflectedY = ImageMath.reflectTriangle(y, height);
                        return pixels[(reflectedY * width) + x];
                }
            } else {
                // both x and y are OK
                return pixels[((y * width) + x)];
            }
        }
    }

    private int getPixelNN(int[] inPixels, int srcWidth, int srcHeight, int srcX, int srcY, float[] out) {
        if ((out[0] < 0) || (srcX >= srcWidth)) {
            // x out of range
            if ((out[1] < 0) || (srcY >= srcHeight)) {
                // y also out of range
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(ImageMath.mod(srcY, srcHeight) * srcWidth) + ImageMath.mod(srcX, srcWidth)];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(srcX, srcWidth);
                        int reflectedY = ImageMath.reflectTriangle(srcY, srcHeight);
                        return inPixels[(reflectedY * srcWidth) + reflectedX];
                }
            } else {
                // x out of range, but y is OK
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(srcY * srcWidth) + ImageMath.mod(srcX, srcWidth)];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(srcY * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)];
                    case REFLECT:
                        int reflectedX = ImageMath.reflectTriangle(srcX, srcWidth);
                        return inPixels[(srcY * srcWidth) + reflectedX];
                }
            }
        } else {
            // x in range
            if ((out[1] < 0) || (srcY >= srcHeight)) {
                // ... but y isn't
                switch(edgeAction) {
                    case TRANSPARENT:
                    default:
                        return 0;
                    case WRAP_AROUND:
                        return inPixels[(ImageMath.mod(srcY, srcHeight) * srcWidth) + srcX];
                    case REPEAT_EDGE_PIXELS:
                        return inPixels[(ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + srcX];
                    case REFLECT:
                        int reflectedY = ImageMath.reflectTriangle(srcY, srcHeight);
                        return inPixels[(reflectedY * srcWidth) + srcX];
                }
            } else {
                // both x and y are OK
                int i = (srcWidth * srcY) + srcX;
                return inPixels[i];
            }
        }
    }
}


/**
 * Alle Rechte vorbehalten / All Rights Reserved.  Use is subject to license terms.
 *
 * <http://example.com>
 */
package com.github.anba.es6draft.runtime.internal;

import java.io.PrintWriter;
import java.io.Reader;

public interface Console {

    /**
     * Prints the format string to the console output writer.
     *
     * @param format
     *            the format string
     * @param args
     *            the format string arguments
     */
    void printf(String format, Object... args);

    /**
     * Flushes the console output writer.
     */
    void flush();

    /**
     * Reads a single line from the console input reader.
     *
     * @return the line string or {@code null} if no input available
     */
    String readLine();

    /**
     * Reads a single line from the console input reader.
     *
     * @param prompt
     *            the optional command line prompt
     * @return the line string or {@code null} if no input available
     */

    /**
     * Returns the reader ({@code stdin}) bound to this console object.
     *
     * @return the console reader
     */
    Reader reader();

    /**
     * Returns the writer ({@code stdout}) bound to this console object.
     *
     * @return the console writer
     */
    PrintWriter writer();

    /**
     * Returns the error writer ({@code stderr}) bound to this console object.
     *
     * @return the console error writer
     */
    PrintWriter errorWriter();
}


protected void updateLaunchConfigurationDialog() {
        if (!isUpdatingFields)
            super.updateLaunchConfigurationDialog();
    }

/**
 * ****************************************************************************
 *
 *  Contributors:
 *      The TeXlipse team - initial API and implementation
 * *****************************************************************************
 */
package org.eclipse.texlipse.viewer;

import java.io.File;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.texlipse.TexlipsePlugin;

/**
 * The tab containing Latex previewer configuration.
 *
 * @author Kimmo Karlsson
 * @author Tor Arne Vestbø
 */
public class TexLaunchConfigurationTab extends AbstractLaunchConfigurationTab {

    // list of viewers
    private Combo choiceCombo;

    // the viewer command
    private Text commandField;

    // the viewer arguments
    private Text argumentField;

    // button to launch the file browser
    private Button commandBrowserButton;

    // a copy of the viewer attributes
    private ViewerAttributeRegistry registry;

    private DDEGroup ddeCloseGroup;

    private DDEGroup ddeViewGroup;

    // true if we are populating the whole tab with new information
    private boolean isUpdatingFields = false;

    public TexLaunchConfigurationTab() {
        registry = new ViewerAttributeRegistry();
    }

    /**
     * Creates the top level control for this launch configuration
     * tab under the given parent composite.  This method is called once on
     * tab creation, after setLaunchConfigurationDialog
     * is called.
     *

     * Implementors are responsible for ensuring that
     * the created control can be accessed via getControl
     *

     *
     * @param parent the parent composite
     */
    public void createControl(Composite parent) {
        Composite composite = new Composite(parent, SWT.FILL);
        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        composite.setLayout(layout);
        composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        createVerticalSpacer(composite, 3);
        Label choiceLabel = new Label(composite, SWT.LEFT);
        choiceLabel.setText(TexlipsePlugin.getResourceString("launchTabChoiceLabel"));
        choiceLabel.setToolTipText(TexlipsePlugin.getResourceString("launchTabChoiceTooltip"));
        choiceLabel.setLayoutData(new GridData());
        choiceCombo = new Combo(composite, SWT.DROP_DOWN);
        choiceCombo.setToolTipText(TexlipsePlugin.getResourceString("launchTabChoiceTooltip"));
        GridData cgd = new GridData();
        cgd.horizontalSpan = 2;
        choiceCombo.setLayoutData(cgd);
        String[] viewers = registry.getViewerList();
        choiceCombo.setItems(viewers);
        choiceCombo.select(registry.getActiveViewerIndex(viewers));
        choiceCombo.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent e) {
                updateFields(choiceCombo.getSelectionIndex());
            }
        });
        createVerticalSpacer(composite, 3);
        Label commandLabel = new Label(composite, SWT.LEFT);
        commandLabel.setText(TexlipsePlugin.getResourceString("launchTabCommandLabel"));
        commandLabel.setToolTipText(TexlipsePlugin.getResourceString("launchTabCommandTooltip"));
        commandLabel.setLayoutData(new GridData());
        commandField = new Text(composite, SWT.SINGLE | SWT.WRAP | SWT.BORDER);
        commandField.setToolTipText(TexlipsePlugin.getResourceString("launchTabCommandTooltip"));
        commandField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
        commandField.addFocusListener(new FocusAdapter() {

            public void focusLost(FocusEvent e) {
                File f = new File(commandField.getText());
                if (!f.exists()) {
                    setErrorMessage(TexlipsePlugin.getResourceString("launchTabCommandError"));
                }
            }
        });
        commandField.addModifyListener(new ModifyListener() {

            public void modifyText(ModifyEvent e) {
                updateLaunchConfigurationDialog();
            }
        });
        commandBrowserButton = new Button(composite, SWT.PUSH);
        commandBrowserButton.setText(JFaceResources.getString("openChange"));
        commandBrowserButton.setToolTipText(TexlipsePlugin.getResourceString("launchTabCommandTooltip"));
        commandBrowserButton.setLayoutData(new GridData());
        commandBrowserButton.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent e) {
                FileDialog dialog = new FileDialog(commandBrowserButton.getShell(), SWT.OPEN);
                String file = dialog.open();
                if (file != null && file.length() > 0) {
                    File f = new File(file);
                    if (f.exists()) {
                        commandField.setText(file);
                    }
                }
            }
        });
        createVerticalSpacer(composite, 3);
        Label argumentLabel = new Label(composite, SWT.LEFT);
        argumentLabel.setText(TexlipsePlugin.getResourceString("launchTabArgumentsLabel"));
        argumentLabel.setToolTipText(TexlipsePlugin.getResourceString("launchTabArgumentsTooltip"));
        argumentLabel.setLayoutData(new GridData());
        argumentField = new Text(composite, SWT.SINGLE | SWT.WRAP | SWT.BORDER);
        argumentField.setToolTipText(TexlipsePlugin.getResourceString("launchTabArgumentsTooltip"));
        argumentField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL));
        argumentField.addModifyListener(new ModifyListener() {

            public void modifyText(ModifyEvent e) {
                updateLaunchConfigurationDialog();
            }
        });
        addDDEGroups(composite);
        setControl(composite);
    }

    /**
     * Handle the change of selected item in the viewer list.
     * @param selectionIndex currently selected item
     */
    private void updateFields(int selectionIndex) {
        isUpdatingFields = true;
        registry.setCommand(commandField.getText());
        registry.setArguments(argumentField.getText());
        registry.setDDEViewCommand(ddeViewGroup.command.getText());
        registry.setDDEViewServer(ddeViewGroup.server.getText());
        registry.setDDEViewTopic(ddeViewGroup.topic.getText());
        registry.setDDECloseCommand(ddeCloseGroup.command.getText());
        registry.setDDECloseServer(ddeCloseGroup.server.getText());
        registry.setDDECloseTopic(ddeCloseGroup.topic.getText());
        String viewer = choiceCombo.getItem(selectionIndex);
        registry.setActiveViewer(viewer);
        String command = registry.getCommand();
        if (command == null) {
            command = "";
        }
        commandField.setText(command);
        String arguments = registry.getArguments();
        if (arguments == null) {
            arguments = "";
        }
        argumentField.setText(arguments);
        ddeViewGroup.command.setText(registry.getDDEViewCommand());
        ddeViewGroup.server.setText(registry.getDDEViewServer());
        ddeViewGroup.topic.setText(registry.getDDEViewTopic());
        ddeCloseGroup.command.setText(registry.getDDECloseCommand());
        ddeCloseGroup.server.setText(registry.getDDECloseServer());
        ddeCloseGroup.topic.setText(registry.getDDECloseTopic());
        updateLaunchConfigurationDialog();
        isUpdatingFields = false;
    }

    /**
     * Initializes the given launch configuration with
     * default values for this tab. This method
     * is called when a new launch configuration is created
     * such that the configuration can be initialized with
     * meaningful values. This method may be called before this
     * tab's control is created.
     *
     * If the configuration parameter contains an attribute named
     * 'viewerCurrent', the tab is initialized with the default values
     * for the given viewer. The given viewer is expected to exist.
     *
     * @param configuration launch configuration
     */
    public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
        try {
            String viewer = configuration.getAttribute("viewerCurrent", registry.getActiveViewer());
            registry.setActiveViewer(viewer);
            configuration.setAttribute(ViewerAttributeRegistry.VIEWER_CURRENT, viewer);
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_COMMAND, registry.getCommand());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_ARGUMENTS, registry.getArguments());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_VIEW_COMMAND, registry.getDDEViewCommand());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_VIEW_SERVER, registry.getDDEViewServer());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_VIEW_TOPIC, registry.getDDEViewTopic());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_CLOSE_COMMAND, registry.getDDECloseCommand());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_CLOSE_SERVER, registry.getDDECloseServer());
            configuration.setAttribute(viewer + ViewerAttributeRegistry.ATTRIBUTE_DDE_CLOSE_TOPIC, registry.getDDECloseTopic());
        } catch (CoreException e) {
            TexlipsePlugin.log("Initializing launch configuration", e);
        }
    }

    /**
     * Initializes this tab's controls with values from the given
     * launch configuration. This method is called when
     * a configuration is selected to view or edit, after this
     * tab's control has been created.
     *
     * @param configuration launch configuration
     */
    public void initializeFrom(ILaunchConfiguration configuration) {
        try {
            registry.setValues(configuration.getAttributes());
            String[] viewers = registry.getViewerList();
            choiceCombo.setItems(viewers);
            choiceCombo.select(registry.getActiveViewerIndex(viewers));
            commandField.setText(registry.getCommand());
            argumentField.setText(registry.getArguments());
            ddeViewGroup.command.setText(registry.getDDEViewCommand());
            ddeViewGroup.server.setText(registry.getDDEViewServer());
            ddeViewGroup.topic.setText(registry.getDDEViewTopic());
            ddeCloseGroup.command.setText(registry.getDDECloseCommand());
            ddeCloseGroup.server.setText(registry.getDDECloseServer());
            ddeCloseGroup.topic.setText(registry.getDDECloseTopic());
        } catch (CoreException e) {
            TexlipsePlugin.log("Reading launch configuration", e);
        }
    }

    /**
     * Copies values from this tab into the given
     * launch configuration.
     *
     * @param configuration launch configuration
     */
    public void performApply(ILaunchConfigurationWorkingCopy configuration) {
        registry.setActiveViewer(choiceCombo.getItem(choiceCombo.getSelectionIndex()));
        registry.setCommand(commandField.getText());
        registry.setArguments(argumentField.getText());
        registry.setDDEViewCommand(ddeViewGroup.command.getText());
        registry.setDDEViewServer(ddeViewGroup.server.getText());
        registry.setDDEViewTopic(ddeViewGroup.topic.getText());
        registry.setDDECloseCommand(ddeCloseGroup.command.getText());
        registry.setDDECloseServer(ddeCloseGroup.server.getText());
        registry.setDDECloseTopic(ddeCloseGroup.topic.getText());
        configuration.setAttributes(registry.asMap());
    }

    /**
     * Returns the image of this tab.
     * @return the image of this tab
     */
    public Image getImage() {
        return TexlipsePlugin.getImage("sample");
    }

    /**
     * Returns the name of this tab.
     *
     * @return the name of this tab
     */
    public String getName() {
        return TexlipsePlugin.getResourceString("launchTabTitle");
    }

    /**
     * Only update the fields if we are done filling them in
     */

    /**
     * Creates the two groups for DDE view and close
     *
     * @param composite
     *            parent component
     */
    private void addDDEGroups(Composite composite) {
        ddeViewGroup = new DDEGroup(composite, TexlipsePlugin.getResourceString("preferenceViewerDDEViewLabel"), TexlipsePlugin.getResourceString("preferenceViewerDDEViewTooltip"));
        ddeCloseGroup = new DDEGroup(composite, TexlipsePlugin.getResourceString("preferenceViewerDDECloseLabel"), TexlipsePlugin.getResourceString("preferenceViewerDDECloseTooltip"));
        // Only show DDE configuration if on Win32
        if (Platform.getOS().equals(Platform.OS_WIN32)) {
            ddeViewGroup.setVisible(true);
            ddeCloseGroup.setVisible(true);
        }
    }

    private class DDEGroup extends Composite {

        // Public members since the class is private to the dialog
        public Text command;

        public Text server;

        public Text topic;

        public DDEGroup(Composite parent, String name, String toolTip) {
            super(parent, SWT.NONE);
            setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            ((GridData) getLayoutData()).horizontalSpan = 2;
            setLayout(new GridLayout());
            Group group = new Group(this, SWT.SHADOW_IN);
            group.setText(name);
            group.setToolTipText(toolTip);
            group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            group.setLayout(new GridLayout(4, false));
            Label ddeCommandLabel = new Label(group, SWT.LEFT);
            ddeCommandLabel.setText(TexlipsePlugin.getResourceString("preferenceViewerDDECommandLabel"));
            ddeCommandLabel.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDECommandTooltip"));
            ddeCommandLabel.setLayoutData(new GridData());
            command = new Text(group, SWT.SINGLE | SWT.BORDER);
            command.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDECommandTooltip"));
            command.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            command.addModifyListener(new ModifyListener() {

                public void modifyText(ModifyEvent e) {
                    updateLaunchConfigurationDialog();
                }
            });
            ((GridData) command.getLayoutData()).horizontalSpan = 3;
            Label ddeServerLabel = new Label(group, SWT.LEFT);
            ddeServerLabel.setText(TexlipsePlugin.getResourceString("preferenceViewerDDEServerLabel"));
            ddeServerLabel.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDEServerTooltip"));
            ddeServerLabel.setLayoutData(new GridData());
            server = new Text(group, SWT.SINGLE | SWT.BORDER);
            server.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDEServerTooltip"));
            server.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            server.addModifyListener(new ModifyListener() {

                public void modifyText(ModifyEvent e) {
                    updateLaunchConfigurationDialog();
                }
            });
            Label ddeTopicLabel = new Label(group, SWT.LEFT);
            ddeTopicLabel.setText(TexlipsePlugin.getResourceString("preferenceViewerDDETopicLabel"));
            ddeTopicLabel.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDETopicTooltip"));
            ddeTopicLabel.setLayoutData(new GridData());
            topic = new Text(group, SWT.SINGLE | SWT.BORDER);
            topic.setToolTipText(TexlipsePlugin.getResourceString("preferenceViewerDDETopicTooltip"));
            topic.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            topic.addModifyListener(new ModifyListener() {

                public void modifyText(ModifyEvent e) {
                    updateLaunchConfigurationDialog();
                }
            });
            setVisible(false);
        }
    }
}


public void setName(String name1) {
        this.name = name1;
    }

package edu.internet2.middleware.grouper.ws.soap_v2_0;

/**
 * attribute sent back to caller
 * @author mchyzer
 */
public class WsAttribute {

    /**
     * name of attribute
     */
    private String name;

    /**
     * value of attribute
     */
    private String value;

    /**
     * name of attribute
     * @return the name
     */
    public String getName() {
        return this.name;
    }

    /**
     * value of attribute
     * @return the value
     */
    public String getValue() {
        return this.value;
    }

    /**
     * name of attribute
     * @param name1 the name to set
     */

    /**
     * @param value1 the value to set
     */
    public void setValue(String value1) {
        this.value = value1;
    }
}


protected void addParameter(EstimatedParameter p) {
        parameters.add(p);
    }

package org.apache.commons.math.estimation;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Simple implementation of the {@link EstimationProblem
 * EstimationProblem} interface for boilerplate data handling.
 *
This class only handles parameters and measurements
 * storage and unbound parameters filtering. It does not compute
 * anything by itself. It should either be used with measurements
 * implementation that are smart enough to know about the
 * various parameters in order to compute the partial derivatives
 * appropriately. Since the problem-specific logic is mainly related to
 * the various measurements models, the simplest way to use this class
 * is by extending it and using one internal class extending
 * {@link WeightedMeasurement WeightedMeasurement} for each measurement
 * type. The instances of the internal classes would have access to the
 * various parameters and their current estimate.

 *
 * @version $Revision: 627989 $ $Date: 2008-02-15 03:04:02 -0700 (Fri, 15 Feb 2008) $
 * @since 1.2
 */
public class SimpleEstimationProblem implements EstimationProblem {

    /**
     * Build an empty instance without parameters nor measurements.
     */
    public SimpleEstimationProblem() {
        parameters = new ArrayList();
        measurements = new ArrayList();
    }

    /**
     * Get all the parameters of the problem.
     * @return parameters
     */
    public EstimatedParameter[] getAllParameters() {
        return (EstimatedParameter[]) parameters.toArray(new EstimatedParameter[parameters.size()]);
    }

    /**
     * Get the unbound parameters of the problem.
     * @return unbound parameters
     */
    public EstimatedParameter[] getUnboundParameters() {
        // filter the unbound parameters
        List unbound = new ArrayList(parameters.size());
        for (Iterator iterator = parameters.iterator(); iterator.hasNext(); ) {
            EstimatedParameter p = (EstimatedParameter) iterator.next();
            if (!p.isBound()) {
                unbound.add(p);
            }
        }
        // convert to an array
        return (EstimatedParameter[]) unbound.toArray(new EstimatedParameter[unbound.size()]);
    }

    /**
     * Get the measurements of an estimation problem.
     * @return measurements
     */
    public WeightedMeasurement[] getMeasurements() {
        return (WeightedMeasurement[]) measurements.toArray(new WeightedMeasurement[measurements.size()]);
    }

    /**
     * Add a parameter to the problem.
     * @param p parameter to add
     */

    /**
     * Add a new measurement to the set.
     * @param m measurement to add
     */
    protected void addMeasurement(WeightedMeasurement m) {
        measurements.add(m);
    }

    /**
     * Estimated parameters.
     */
    private final List parameters;

    private final List measurements;
}


for (Iterator iterator = parameters.iterator(); iterator.hasNext(); ) {
            EstimatedParameter p = (EstimatedParameter) iterator.next();
            if (!p.isBound()) {
                unbound.add(p);
            }
        }

package org.apache.commons.math.estimation;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Simple implementation of the {@link EstimationProblem
 * EstimationProblem} interface for boilerplate data handling.
 *
This class only handles parameters and measurements
 * storage and unbound parameters filtering. It does not compute
 * anything by itself. It should either be used with measurements
 * implementation that are smart enough to know about the
 * various parameters in order to compute the partial derivatives
 * appropriately. Since the problem-specific logic is mainly related to
 * the various measurements models, the simplest way to use this class
 * is by extending it and using one internal class extending
 * {@link WeightedMeasurement WeightedMeasurement} for each measurement
 * type. The instances of the internal classes would have access to the
 * various parameters and their current estimate.

 *
 * @version $Revision: 627989 $ $Date: 2008-02-15 03:04:02 -0700 (Fri, 15 Feb 2008) $
 * @since 1.2
 */
public class SimpleEstimationProblem implements EstimationProblem {

    /**
     * Build an empty instance without parameters nor measurements.
     */
    public SimpleEstimationProblem() {
        parameters = new ArrayList();
        measurements = new ArrayList();
    }

    /**
     * Get all the parameters of the problem.
     * @return parameters
     */
    public EstimatedParameter[] getAllParameters() {
        return (EstimatedParameter[]) parameters.toArray(new EstimatedParameter[parameters.size()]);
    }

    /**
     * Get the unbound parameters of the problem.
     * @return unbound parameters
     */
    public EstimatedParameter[] getUnboundParameters() {
        // filter the unbound parameters
        List unbound = new ArrayList(parameters.size());

        // convert to an array
        return (EstimatedParameter[]) unbound.toArray(new EstimatedParameter[unbound.size()]);
    }

    /**
     * Get the measurements of an estimation problem.
     * @return measurements
     */
    public WeightedMeasurement[] getMeasurements() {
        return (WeightedMeasurement[]) measurements.toArray(new WeightedMeasurement[measurements.size()]);
    }

    /**
     * Add a parameter to the problem.
     * @param p parameter to add
     */
    protected void addParameter(EstimatedParameter p) {
        parameters.add(p);
    }

    /**
     * Add a new measurement to the set.
     * @param m measurement to add
     */
    protected void addMeasurement(WeightedMeasurement m) {
        measurements.add(m);
    }

    /**
     * Estimated parameters.
     */
    private final List parameters;

    private final List measurements;
}


package org.apache.aurora.scheduler.storage.durability;

import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.inject.Inject;
import org.apache.aurora.common.inject.TimedInterceptor.Timed;
import org.apache.aurora.common.stats.SlidingStats;
import org.apache.aurora.gen.storage.Op;
import org.apache.aurora.scheduler.base.SchedulerException;
import org.apache.aurora.scheduler.events.EventSink;
import org.apache.aurora.scheduler.storage.AttributeStore;
import org.apache.aurora.scheduler.storage.CronJobStore;
import org.apache.aurora.scheduler.storage.HostMaintenanceStore;
import org.apache.aurora.scheduler.storage.JobUpdateStore;
import org.apache.aurora.scheduler.storage.QuotaStore;
import org.apache.aurora.scheduler.storage.SchedulerStore;
import org.apache.aurora.scheduler.storage.Storage;
import org.apache.aurora.scheduler.storage.Storage.MutateWork.NoResult;
import org.apache.aurora.scheduler.storage.Storage.NonVolatileStorage;
import org.apache.aurora.scheduler.storage.TaskStore;
import org.apache.aurora.scheduler.storage.durability.Persistence.PersistenceException;
import org.slf4j.LoggerFactory;
import static java.util.Objects.requireNonNull;

/**
 * A storage implementation that ensures storage mutations are written to a persistence layer.
 *
 *
In the classic write-ahead log usage we'd perform mutations as follows:
 *

 *
record op

 *
perform op locally

 *
persist ops

 *

 *
 *
Writing the operation to persistences ensures we have a record of our mutation in case we
 * should need to recover state later after a crash or on a new host (assuming the scheduler is
 * distributed).  We then apply the mutation to a local (in-memory) data structure for serving fast
 * read requests.
 *
 *
This implementation leverages a local transaction to handle this:
 *

 *
start local transaction

 *
perform op locally (uncommitted!)

 *
write op to persistence

 *

 *
 *
If the op fails to apply to local storage we will never persist the op, and if the op
 * fails to persist, it'll throw and abort the local storage operation as well.
 */
public class DurableStorage implements NonVolatileStorage {

    /**
     * A maintainer for context about open transactions. Assumes that an external entity is
     * responsible for opening and closing transactions.
     */
    interface TransactionManager {

        /**
         * Checks whether there is an open transaction.
         *
         * @return {@code true} if there is an open transaction, {@code false} otherwise.
         */

        /**
         * Adds an operation to the existing transaction.
         *
         * @param op Operation to include in the existing transaction.
         */
        void log(Op op);
    }

    private final Persistence persistence;

    private final Storage writeBehindStorage;

    private final ReentrantLock writeLock;

    private final ThriftBackfill thriftBackfill;

    private final WriteRecorder writeRecorder;

    private TransactionRecorder transaction = null;

    private final SlidingStats writerWaitStats = new SlidingStats("storage_write_lock_wait", "ns");

    @Inject
    DurableStorage(Persistence persistence, @Volatile Storage delegateStorage, @Volatile SchedulerStore.Mutable schedulerStore, @Volatile CronJobStore.Mutable jobStore, @Volatile TaskStore.Mutable taskStore, @Volatile QuotaStore.Mutable quotaStore, @Volatile AttributeStore.Mutable attributeStore, @Volatile JobUpdateStore.Mutable jobUpdateStore, @Volatile HostMaintenanceStore.Mutable hostMaintenanceStore, EventSink eventSink, ReentrantLock writeLock, ThriftBackfill thriftBackfill) {
        this.persistence = requireNonNull(persistence);
        // DurableStorage has two distinct operating modes: pre- and post-recovery.  When recovering,
        // we write directly to the writeBehind stores since we are replaying what's already persisted.
        // After that, all writes must succeed in Persistence before they may be considered successful.
        this.writeBehindStorage = requireNonNull(delegateStorage);
        this.writeLock = requireNonNull(writeLock);
        this.thriftBackfill = requireNonNull(thriftBackfill);
        TransactionManager transactionManager = new TransactionManager() {

            @Override
            public boolean hasActiveTransaction() {
                return transaction != null;
            }

            @Override
            public void log(Op op) {
                transaction.add(op);
            }
        };
        this.writeRecorder = new WriteRecorder(transactionManager, schedulerStore, jobStore, taskStore, quotaStore, attributeStore, jobUpdateStore, hostMaintenanceStore, LoggerFactory.getLogger(WriteRecorder.class), eventSink);
    }

    @Override
    @Timed("scheduler_storage_prepare")
    public synchronized void prepare() {
        writeBehindStorage.prepare();
        persistence.prepare();
    }

    @Override
    @Timed("scheduler_storage_start")
    public void start(final MutateWork.NoResult.Quiet initializationLogic) {
        writeLock.lock();
        try {
            // We recover directly into the forwarded system to avoid persisting replayed operations.
            writeBehindStorage.write((NoResult.Quiet) this::recover);
            // Now that we're recovered we should persist any mutations done in initializationLogic, so
            // run it in one of our transactions.
            write(initializationLogic);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public void stop() {
    }

    @Timed("scheduler_storage_recover")
    void recover(MutableStoreProvider stores) throws RecoveryFailedException {
        try {
            Loader.load(stores, thriftBackfill, persistence.recover());
        } catch (PersistenceException e) {
            throw new RecoveryFailedException(e);
        }
    }

    private static final class RecoveryFailedException extends SchedulerException {

        RecoveryFailedException(Throwable cause) {
            super(cause);
        }
    }

    private <T, E extends Exception> T doInTransaction(final MutateWork<T, E> work) throws StorageException, E {
        // The transaction has already been set up so we just need to delegate with our store provider
        // so any mutations may be persisted.
        if (transaction != null) {
            return work.apply(writeRecorder);
        }
        transaction = new TransactionRecorder();
        try {
            return writeBehindStorage.write(unused -> {
                T result = work.apply(writeRecorder);
                List<Op> ops = transaction.getOps();
                if (!ops.isEmpty()) {
                    try {
                        persistence.persist(ops.stream());
                    } catch (PersistenceException e) {
                        throw new StorageException("Failed to persist storage changes", e);
                    }
                }
                return result;
            });
        } finally {
            transaction = null;
        }
    }

    @Override
    public <T, E extends Exception> T write(final MutateWork<T, E> work) throws StorageException, E {
        long waitStart = System.nanoTime();
        writeLock.lock();
        try {
            writerWaitStats.accumulate(System.nanoTime() - waitStart);
            return doInTransaction(work);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    public <T, E extends Exception> T read(Work<T, E> work) throws StorageException, E {
        return writeBehindStorage.read(work);
    }
}